I have the following code where I am trying to update the value for the select tag.
constructor(props){
super(props)
this.state={value: 'Male'}
}
handleChange = (event) => {
this.setState({value: event.target.value})
this.props.selectCB(this.state.value)
console.log(this.state.value)
}
render(){
return (
<label>GENDER: <br/>
<select value={this.state.value} onChange={this.handleChange}>
<option value='Male'>Male</option>
<option value='Female'>Female</option>
<option value='Not Specified'>Not-Specified</option>
<option value='Non Binary'>Non-Binary</option>
</select>
<br/>
</label>
)
}
}
class NameForm extends React.Component{
constructor(props){
super(props)
this.state = {selectValue: ''}
}
handleSelectCallback = (selectData) => {
this.setState({selectValue: selectData})
}
handleSubmit = (event) => {
console.log('Logged select: ' this.state.selectValue)
alert(`Submitted : ${this.state.selectValue}`)
event.preventDefault()
}
render(){
return <form onSubmit={this.handleSubmit}>
<SelectTag selectCB={this.handleSelectCallback}/>
<input type='submit' value='Submit'></input>
</form>
}
}
function App(){
return <NameForm/>
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(App());
The SelectTag is a child component to NameForm which in turn is rendered by the function App(). The change handler resides in SelectTag while the submit handler is in NameForm. I am trying to get the selected value from SelectTag to the parent NameForm by using a callback handleSelectCallback(). When the data in SelectTag is changed it is not being updated in NameForm.
If I start with the value Male and change it to Female, the value of selectValue in NameTag is still Male. If I change the value again (say to Not Specified), the value of selectValue changes to Female.
(Note: I noticed that this is working properly for other React components. I tested with components that render text boxes and text areas.)
CodePudding user response:
You are sending the old state value through the callback. setState is async.
handleChange = (event) => {
// Schedule an update to the component with a new state value
this.setState({value: event.target.value})
// Callback with the outdated state value
this.props.selectCB(this.state.value)
}
You could just change it to the right value
handleChange = (event) => {
this.setState({value: event.target.value})
this.props.selectCB(event.target.value)
}
Or better yet, remove the state.value because it's not need. Instead keep the state in one place (the parent), and send the value and the callback down.
handleChange = (event) => {
this.props.selectCB(event.target.value)
}
// and
<select value={this.props.value} />
// and
<SelectTag selectCB={this.handleSelectCallback} value={this.state.selectValue} />