React select onChange not changing selected value

11,765

Solution 1

You can use componentDidUpdate() to check if incoming props are different:

componentDidUpdate(nextProps) {
  if (nextProps.agent.team !== this.props.agent.team) {
    this.setState({ selectedTeam: nextProps.agent.team })
  }
}

In componentDidUpdate, nextProps represents the incoming props. This will check if they are different, and the setState will ensure the component re-renders.

Additionally, this will run when the component first receives props, meaning you shouldn't have to set the default value in state.

Note: You are mixing methods, by using querySelector to get the value of the select menu. Ideally, you would use the value in state - that way you can ensure that you are setting and getting the right value, rather than mixing methods and possibly getting the non-updated version.

Solution 2

Need to tell React to trigger the function onClick

onClick={() => this.handleOnClick()} <-----

Just a side note to help save on code, you can also use ES6 to bind functions to this by doing an arrow function. It's not 100% for sure if it will be there in the future, but it's widely used so I think they will adopt it.

handleOnClick = () => {
  const selectedTeam = document.querySelector('.team-selection').value

  axios.post( ...ajax stuff... )
}
Share:
11,765

Related videos on Youtube

ryanpitts1
Author by

ryanpitts1

Updated on June 04, 2022

Comments

  • ryanpitts1
    ryanpitts1 almost 2 years

    I have a React component that has some html rendered and part of the html is a select element. The below code works for displaying the default value of the initial select element and changes the selected value when you choose another one.

    My problem is that i have a list of people and when you click on one the values on the section of the page where this is used get updated to that person's values (name, email, etc). Those all update correctly i believe because this.props.agent gets updated. I don't have insight into that code at the moment. My question is that the select element isn't respecting the change in this.props.agent and thus re-selecting the correct saved value for team. I'm sure using state within constructor() isn't the right approach.

    I am new to React so pardon me if my question isn't accurate or explained well enough. But how can i get it to update the pre-selected select option when this.props.agent updates?

    import React from 'react'
    import axios from 'axios'
    
    export class AgentTeam extends React.Component {
        constructor(props) {
            super(props)
    
            this.state = {
                teams: [],
                selectedTeam: this.props.agent.team || ''
            }
    
            this.handleOnClick = this.handleOnClick.bind(this)
            this.handleOnChange = this.handleOnChange.bind(this)
        }
    
        componentDidMount() {
            axios.get(
                ... ajax setup ...
            ).then(response => {
                this.setState({
                    teams: response.data,
                })
            }).catch(error => {
                throw error
            })
        }
    
        handleOnClick() {
            const selectedTeam = document.querySelector('.team-selection').value
    
            axios.post( ...ajax stuff... )
        }
    
        handleOnChange = (event) => {
            this.setState({
                selectedTeam: event.target.value
            })
        }
    
        render() {
            const teamList = this.state.teams.map((team, i) =>
                <option value={team.team_name} key={i}>
                    {team.team_name}
                </option>
            )
    
            return (
                <div>
                    <div className='agent-team-heading'>
                        <span>Team</span>
                    </div>
                    <div className='agent-team-selector'>
                        <select className='team-selection' value={this.state.selectedTeam} onChange={this.handleOnChange}>
                            <option value=''>Assign Team</option>
                            {teamList}
                        </select>
                        <button className="agent-team-button" onClick={this.handleOnClick}>
                            <span>SAVE</span>
                        </button>
                    </div>
                </div>
            )
        }
    }
    
  • varoons
    varoons over 5 years
    Missing parenthesis onClick={() => this.handleOnClick()}
  • ryanpitts1
    ryanpitts1 over 5 years
    So, you're suggesting to save the state of the whole agent instead of just the team?
  • Toby
    Toby over 5 years
    Well, I guess I don't really know what is in agent - if it's a complex object then you'd have to do some deeper checking. Ideally it should be a simple check for something that has changed. But it looks like the data from the API is the teams, so if something in props is changing then you need a method in componentDidUpdate to decide when to re-render - in this case, setting state will force the re-render.
  • Toby
    Toby over 5 years
    I've updated the answer to what (I think) may be a more simple check. For a more accurate answer, you could try recreating at CodeSandbox.
  • ryanpitts1
    ryanpitts1 over 5 years
    This seems to give me what i'm looking for, however, the results i get seem backwards from what i would expect. nextProps.agent.team is showing the team for the agent that was previously selected. And this.props.agent.team is showing the team for the newly selected agent.
  • Toby
    Toby over 5 years
    It's tough to say without being more familiar with the data - if you console.log inside the render() function, you should see it update multiple times as the component mounts, renders and rerenders as props and state updates.