I'm using React Select with Redux Form, and when I change the options(dynamically, passing another prop), the value isn't cleared as I expected.
Is this normal?
Obs: the value isn't in the new options array
I tried to sanitize the value with a function: value={sanitize(props.input.value)}
It works for the visual part(placeholder is shown instead), but when I submit, the old value is sent to the server.
Hi @felippepuhle having trouble understanding where the issue falls. Can you give me a bit more context or a reproducible case? Thanks!
Example:

When I select a value from the first input, options of the second input is updated. So, when I select the state Roraima, the city Acrel芒ndia isn't in the option list anymore ('cause it belongs to Acre state).
In my point of view, the value of the second input must be cleared in this case. Am I wrong?
Thanks!
I see. I would recommend to handle this on your side by stripping the value in the second option when the first one changes. The select is a controlled component so clearing out the other component should be on the user of the component.
I've tried to handle this in my own component, something like this:
<ReactSelect.Async
value={this.sanitize(props.input.value)}
/>
sanitize (value) {
const exists = this.state.options.filter((option) => {
return option[this.props.valueKey] === value[this.props.valueKey]
}).length > 0
return exists ? value : null
}
Visually it works, but somehow it keeps sending the old value to the submit function.
Any ideas?
I can share all the component code if you want...
Select does not call the onChange handler when the input value prop changes. So the state in the redux-store doesn't change.
In addition to updating the options of the "Cidade" select you also must change the form value of "Cidade". I don't have experience with redux-form, but i believe the right thing to look at may be this.
Got it. Any reason to not do that call? Maybe I can work on it.
I'll take a look at normalizer for a while, thanks!
Calling onChange when the value props changes would likely cause race conditions.
In a controlled form the state of the form controls the value prop of the Select. Select.onChange is used to update the form state. The form state and the Select value prop will never go out of sync if you only use the form state to control the Select programmatically.
So in short: not calling onChange when the value prop changes is done on purpose.
Thanks for the explanation @cbergmiller!
I used React Dev Tools and found that actually 'value' keeps updated on the Select state.
So, sanitizing the value should resolve this... But I still can't understand how Select pass this 'old' value to Redux Form, or even if could be something wrong with Redux Form and not with Select...
Any ideas?
Thanks for your time.
Maybe you should post some example code..
React Select is only passing values to Redux form by calling the onChange function with a new value if the user clicks on an option (or clears the select).
_Sanitizing_ the select value prop by passing it thru a function is not the right way IMO. This will allow the form value in the redux store to be different from the value that is displayed by Select. The right way to deal with the problem is to change the form state that is kept in the Redux store when a user selects a new value for _Estado_. By form state i am referring to the options and the value for _Cidade_.
I agree. But I think that's not the right way too. I'm developing reusable components(this one is based on Select2). If I handle this in my component, I'll increase the coupling between two different fields(Estado and Cidade). And this is just one case, if another arise, I'll have to do the same for each different case.
If Select2 have the correct value in their state(only getting the ones that's contained in options, as you can see here), why not call onChange?
Well, you could write an wrapper component or an HOC that changes Select's API for your app. You also could open a PR with the changes that are necessary to implement the behavior you want.
That said, i think that calling an onChange event handler in inside of an React live-cycle-hook when the value prop changes could be considered an anti-pattern (non standard behavior, danger of race conditions).
Of course, @cbergmiller. I'll close this issue for now 'cause it's not a priority task(in the business layer). I'll try to think in another approach too and as soon as possible I'll send a PR.
Thanks for your time, you're really kind.
hi @felippepuhle i have same problem in my project, i want to know what did you do for solving this issue?
I have the solution.
To solve @felippepuhle example of "Estado" and "Cidade" (State/City).
All we need to do is watch Cities change, through Redux Form or Set State.
Then we do an intersect between Old Cities and New Cities loaded (will return only cities that exists on new Cities props)
Then we dispatch CHANGE to Redux Form with the intersected variable.
Then Cities Select will have only SELECTED values that exists on new CITIES props. unchecking others that doesn't exists (this works for multi select too)
I hope this help you folks! I lost 3 hours trying to solve this, hehehe.
import { reduxForm, formValueSelector, Field, change, untouch } from 'redux-form';
componentDidUpdate(prevProps, prevState) {
// everytime this.props.cities be updated (via redux for example), componentDidUpdate will be called.
if (this.props.cities !== prevProps.cities) {
cities_selecteds = this.props.cities_selecteds;
if (this.props.cities_selecteds === undefined) { // we check, because redux form when it is empty, comes undefined. idk why
var cities_selecteds = [];
}
var intersection = this.props.cities.filter(a => cities_selecteds.some(b => a.City.id === b.City.id));
this.props.changeFormInput('myFormName', 'cities', intersection); // this will update our <Field/> value with intersected values. Will return only values that exists on New Cities Prop.
}
}
MyContainer = reduxForm({
form: 'myFormName'
})(MyContainer);
const selector = formValueSelector('myFormName');
const mapStateToProps = state => ({
cities: state.appReducer.cities,
cities_selecteds: selector(state, 'cities') // this is my <Field/> on render function. it is updated automatically by redux form.
})
const mapDispatchToProps = dispatch => ({
changeFormInput(form, input, value) {
dispatch(change(form, input, value));
dispatch(untouch(form, input));
}
})
export default connect(mapStateToProps, mapDispatchToProps)(MyContainer);
Most helpful comment
Example:

When I select a value from the first input, options of the second input is updated. So, when I select the state
Roraima, the cityAcrel芒ndiaisn't in the option list anymore ('cause it belongs toAcrestate).In my point of view, the value of the second input must be cleared in this case. Am I wrong?
Thanks!