简体   繁体   中英

React-select multi select update a prop when no value is selected

I am using react-select library to create a multi-selection menu. When there is no value selected I want a certain style width to be used on the div and when a user starts selecting values from the select dropdown, I want this width to be set to null so that the select component can use it's own auto adjusting width capability. I have the below code but I can't get the width to update synchronously as it updates after the next render call. Not sure how to make it update with the new width immediately. I know setState is async but if you use a callback in the setState function I would imagine it would render with the new state.

...
constructor(props) {
    super(props);
    this.state = {
        dropBoxWidth: { width: 130 },
        selectLength: 1
    }
}
.....
handleChange = selectedOption => {
    if (this.state.selectLength > 0) {
        this.setState(
            { selectedOption, selectLength: selectedOption.length, dropBoxWidth: null },
            () => console.log(`Option selected:`, this.state.selectedOption, this.state.selectLength, this.state.dropBoxWidth)
        );
    } else {
        this.setState({ dropBoxWidth: { width: 130 }, selectLength: 1 }), () =>
            console.log("New Dropbox Width ", this.state.dropBoxWidth)
    }

};
render() {
    return (
        <div style={this.state.dropBoxWidth}>
            <Select
                closeMenuOnSelect={false}
                isMulti
                options={aList}
                onChange={this.handleChange}
                placeholder="Item Select"
            />
        </div>
    )
}

Again to be clear, I want the style width of the div to be set to 130 when there is no value selected. This can be when the page is opened or refreshed(constructor props has the width to 130), and if a user selects values then decides to clear all the selections from the menu.

You can use inital state in styles of component.

<Select
  options={options}
  styles={{
    container: (provided, state) => ({
      ...provided,
      width: !state.hasValue && "130px",
      borderBottom: "1px dotted pink"
    })
  }}
/>

Like here: https://codesandbox.io/s/amazing-dawn-xwcld?file=/src/App.js:290-517

React select styles doc: https://react-select.com/styles

The reason your console.log isn't printing what you'd expect as the dropbox width is that it's not actually being passed as a callback.

If you format the setState call a bit, you can notice that the comma is actually after the closing parenthesis:

this.setState({
    dropBoxWidth: { width: 130 },
    selectLength: 1
}),
() => console.log("New Dropbox Width ", this.state.dropBoxWidth);

But the issue with the code is that you're using stale data when doing the this.state.selectLength comparison. You're not really interested in what the value was previously, but what the value is currently. The selectedOption parameter which react-select passes to you is either an array, or null, so you can check the length from there directly (ie instead of this.state.selectLength > 0 , you can do selectedOption && selectedOption.length > 0 ).

However, since you mentioned that you're interested in the style and length because you want to style the parent div, you don't really need to store the style or the length - you can just store the selected option and derive the state in render() :

const selectedStyle = { width: 130 }

class Selector extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      selectedOption: null,
    };
  }

  handleChange = (selectedOption) => {
    // null or object array
    this.setState({ selectedOption });
  };

  render() {
    const { selectedOption } = this.state;
    const anythingSelected = selectedOption && selectedOption.length > 0;

    return (
      <div style={!anythingSelected ? selectedStyle : null}>
        <Select
          closeMenuOnSelect={false}
          isMulti
          options={aList}
          onChange={this.handleChange}
          placeholder="Item Select"
        />
      </div>
    );
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM