Search code examples
javascriptreactjsstatedropdown

React | Reusable dropdown component | how to get selected option?


Fairly new with react. I'm creating a dropdown button for a Gatsby project. The button toggle works, but I'm having trouble getting the selected value to the parent where I need it.

-Tried lifting the state up, but this resulted in the button not appearing at all. I was a bit confused here so maybe I was doing something wrong.

-Also tried using refs although I wasn't sure if this was the right use case, it worked, however it seems the value is grabbed before it's updated in the child component and I'm not sure how to change or work around this. (the code is currently set up for this)

Are either of these options right? or could anybody steer me in the right direction, thanks.

Dropdown in parent:

this.dropdownRef1 = React.createRef();
componentDidUpdate(){
        console.log("Color Option:" + this.dropdownRef1.current.state.ColorOption)
      }
<DropdownBtn ref={this.dropdownRef1} mainText="Color" options={this.props.pageContext.colors || ['']} />   

DropdownBtn:

export default class refineBtn extends React.Component {
    constructor(props) {
        super(props);
    }
      state = {
        open: false,
        [this.props.mainText + "Option"]: "all", 
    };

    dropdownBtnToggle = () => {
        this.setState((prevState)=> {
            return{open: !prevState.open};
        });
    };

    optionClickHandler = (option) => {
        this.setState(() => {
            console.log(this.props.mainText + " updated to " + option)
            return {[this.props.mainText + "Option"] : option}
        });
       };

    render(){ 
    const options = this.props.options
    console.log("open: " + this.state.open)

return(
    <div>
        <button onClick={this.dropdownBtnToggle} >
            {this.props.mainText}:               
        </button>
        <div className={this.state.open ? 'option open' : "option"} >
            <p key={"all"} onClick={() => this.optionClickHandler("all")}> all</p>
           {options.map(option => (
               <p key={option} onClick={() => this.optionClickHandler(option)}>{option}</p>
            ))}
        </div>       
    </div>
    );
}
}

Solution

  • You can respond to selection by allowing your component to accept a callback.

    class MyComponent extends React.Component {
      constructor(props) {
        super(props)
        this.state = {open: false, value: ''}
      }
    
      render() {
        return (
          <div>
            <div onClick={() => this.setState({open: true})}>{this.state.value}</div>
            <div style={{display: this.state.open ? 'block' : 'none'}}>
              {this.props.options.map((option) => {
                const handleClick = () => {
                  this.setState({open: false, value: option})
                  this.props.onChange(option)
                }
                return (
                  <div key={option} onClick={handleClick} className={this.state.value === option ? 'active' : undefined}>{option}</div>
                )
              })}
            </div>
          </div>
        )
      }
    }
    
    
    
    
    <MyComponent onChange={console.log} options={...}/>