Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(FIX) onValueChange being called twice #369

Closed
Deckstar opened this issue Sep 28, 2020 · 8 comments · Fixed by #368
Closed

(FIX) onValueChange being called twice #369

Deckstar opened this issue Sep 28, 2020 · 8 comments · Fixed by #368

Comments

@Deckstar
Copy link
Contributor

Deckstar commented Sep 28, 2020

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.

Screenshots

ezgif-2-1997a59fb427

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} />
    )
  }
}
@kadiraydinli
Copy link

This issue is present on Android in the new version of the package. It works fine on iOS.

@federicobadini
Copy link

federicobadini commented Jan 16, 2021

This is still an issue.
The way in which onValueChange is 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 the onValueChange function, the onValueChange prop is called before the asynchronous internal state update. If the updated value prop is updated before the internal state is updated, then componentDidUpdate will detect a discrepancy between the previous selected value and the actual value prop, causing another invocation of onValueChange.

Here is a link showing the problem: https://snack.expo.io/L0LhveQem

A possible solution could be transforming the onValueChange function so that the onValueChange prop is invoked after the internal state update has been performed.

onValueChange(value, index) {
  const { onValueChange } = this.props;
  this.setState((prevState) => {
    return { selectedItem: prevState.items[index] }    
  }, () => onValueChange(value, index));
}

In addition, I cannot understand what this line of code is for:

this.props.onValueChange(selectedItem.value, idx);

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
Copy link

sclavijo93 commented Apr 16, 2021

hello @federicobadini! I've only commented this line and it's not being called twice anymore but only on iOS

this.props.onValueChange(selectedItem.value, idx);

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
Copy link

Why is this line still a part of the code?

@ogheneovo12
Copy link

Issue still persist

@GaetanFauconnier85
Copy link

Still have the issue

1 similar comment
@wbwlkr
Copy link

wbwlkr commented Nov 28, 2023

Still have the issue

@Fosol
Copy link

Fosol commented Oct 31, 2024

Issue still exists

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
9 participants