Repository navigation
(FIX) onValueChange being called twice #369
Description
Hello! 🙂
As some other users have noted, it seems that there is often an issue with this library where the "onValueChange" function is called twice. (For example, see issues #311 , #265 , #242 , #180 , #112 ).
In my case, I had this issue while using the component with reduxForm, which made the component either: 1) bounce back to the previous value every time I tried to select something on iOS, or 2) simply not change anything when selecting a value on Android. (Probably the same thing was happening under the hood, the Android picker just wasn't animated).
I have solved the issue in my local app by replacing getDerivedStateFromProps with compononentDidUpdate in the index.js file of the react-native-picker-select component. I have opened a pull request ( #368 ) with the hope that it may solve others' problems as well.
Describe the bug
The picker doesn't work because the onValueChange call back is called twice, making the selected value reset itself each time. (See GIF).
To Reproduce
Create a custom Field component with the Redux Form library (such as the one I added below). Try to select a value on iOS or Android.
Expected behavior
New value is selected with no problems.
Actual behavior
Value is selected, but the onValueChange callback is immediately called again, forcing the value to go back to its previous state.
Additional details
- Device: iPhone11 simulator (or Android through AVD)
- OS: iOS14 (or Android)
- react-native-picker-select version: latest
- react-native version: 0.63
- expo sdk version: n/a
Reproduction and/or code sample
export class PickerField extends PureComponent<BaseFieldProps & PickerSelectProps> {
getStyle = (params: { active?: boolean, dirty: boolean, invalid: boolean, style: any }) => {
const { active, dirty, invalid, style } = params;
let styleObj = { ...styles.inputContainerStyle, ...{ color: Colors.black } };
if (active) {
styleObj = { ...styleObj, ...styles.inputBoxActive }
}
if (dirty) {
styleObj = { ...styleObj, ...styles.inputBoxDirty }
}
if (invalid) {
styleObj = { ...styleObj, ...styles.invalidBox }
}
if (style) {
styleObj = { ...styleObj, ...style, }
}
return styleObj;
}
renderPicker = ({ input, meta }: WrappedFieldProps) => {
const { items, style, ...rest } = this.props;
const { onChange, value } = input;
const { invalid, active, dirty, } = meta;
const combinedStyle = this.getStyle({ active, dirty, invalid, style });
return (
<RNPickerSelect
value={value}
items={items}
onValueChange={onChange}
style={{
chevron: { display: 'none' },
inputIOS: combinedStyle,
inputAndroid: combinedStyle,
iconContainer: {
top: '50%',
right: '2%',
transform: [{ translateY: -(1 / 2) * this.iconHeight }],
},
}}
// placeholder={{ label: I18n.t("SelectAnItem") }}
useNativeAndroidPickerStyle={false}
{...rest}
/>
)
}
render() {
const { name, validate } = this.props;
return (
<Field name={name} component={this.renderPicker} validate={validate} />
)
}
}

Activity
kadiraydinli commentedon Nov 18, 2020
This issue is present on Android in the new version of the package. It works fine on iOS.
federicobadini commentedon Jan 16, 2021
This is still an issue.
The way in which
onValueChangeis structured opens to a possible race condition between the internal state update and value prop coming from the parent component. To be more precise, when a controlled component triggers theonValueChangefunction, theonValueChangeprop is called before the asynchronous internal state update. If the updatedvalueprop is updated before the internal state is updated, thencomponentDidUpdatewill detect a discrepancy between the previous selected value and the actual value prop, causing another invocation ofonValueChange.Here is a link showing the problem: https://snack.expo.io/L0LhveQem
A possible solution could be transforming the
onValueChangefunction so that theonValueChangeprop is invoked after the internal state update has been performed.In addition, I cannot understand what this line of code is for:
react-native-picker-select/src/index.js
Line 161 in ca6488c
I think everything will work fine even without this line. Am I wrong?
If you are ok with these observation I can provide a small PR to fix.
sclavijo93 commentedon Apr 16, 2021
hello @federicobadini! I've only commented this line and it's not being called twice anymore but only on iOS
react-native-picker-select/src/index.js
Line 161 in ca6488c
I don't understand what that line is for either
update
Sorry, was my mistake on Android, now it is not being called twice in both platforms by commenting that line
TheRealStriker commentedon May 4, 2023
Why is this line still a part of the code?
ogheneovo12 commentedon Sep 1, 2023
Issue still persist
GaetanFauconnier85 commentedon Sep 5, 2023
Still have the issue
wbwlkr commentedon Nov 28, 2023
Still have the issue
Fosol commentedon Oct 31, 2024
Issue still exists