Solo Solo - 3 months ago 70
React JSX Question

Dropdown, React Router and back button

This small component changes URL when you select something from dropdown. Everything works correctly.. Except back button. Everything else changes if I press it but dropdown doesn't change.

How exactly?


  • If I go to landing page, default value is All

  • Now I select Red

  • Now Blue

  • Red again

  • Finally Blue

  • Now, if I click back button, dropdown always shows last selected value (Blue in my example)



How to overcome this issue?




class MyComponent extends React.Component {

constructor (props) {
super(props)
this.state = {
selected: {
// This only affects dropdown if landing to page
value: this.props.params.color, // Get param from url
label: // Some irrelevant uppercase magic here
}
}
}

static defaultProps = {
colors: [
{value: 'all', label: 'All'},
{value: 'red', label: 'Red'},
{value: 'blue', label: 'Blue'}
]
}

render() {
return (
<Dropdown
options={this.props.colors} {/* All options */}
value={this.props.selected} {/* Selected option */}
onChange={this.handleSelect.bind(this)}
/>
)
}

handleSelect(color) {
this.setState({selected: color})
browserHistory.push(`/${color.value}`)
}
}

Answer

Your issue is that you are using state to manage the selected prop of your Dropdown component, however the router does not update this when you navigate back / forward.

Instead remove state entirely from your component and use the router to detect the selected item directly:

import { find } from 'lodash';

class MyComponent extends React.Component {

    static defaultProps = {
        colors: [
            {value: 'all', label: 'All'},
            {value: 'red', label: 'Red'},
            {value: 'blue', label: 'Blue'}
        ]
    }

    getSelected() {
        const colours = this.props.colours
        const selectedColour = this.props.params.colour

        // Find the option matching the route param, or
        // return a default value when the colour is not found
        return find(colours, { value: selectedColour }) || colours[0];
    }

    render() {
        const selectedOption = this.getSelected();
        return (
            <div>
                <Dropdown 
                    options={ this.props.colors } {/* All options */}
                    value={ selectedOption } {/* Selected option */}
                    onChange={ this.handleSelect.bind(this) } 
                />
                <p>You selected: { selectedOption.label }</p>
            </div>
        )
    }

    handleSelect(color) {
        browserHistory.push(`/${color.value}`)
    }
}