react-native-picker / picker

Picker is a cross-platform UI component for selecting an item from a list of options.
MIT License
1.49k stars 280 forks source link

select lead to infinite loop on android, when using together with recoil #419

Open wtlyu opened 2 years ago

wtlyu commented 2 years ago

Example Code:

  const [selectedLanguage, setSelectedLanguage] = useRecoilState(globalStore.selectedLanguage)

  <Picker
    style={[styles.formitem_value, styles.formitem_picker]}
    selectedValue={selectedLanguage}
    onValueChange={(itemValue, itemIndex) => setSelectedLanguage(itemValue)}>
    <Picker.Item label='Java' value='java' />
    <Picker.Item label='JavaScript' value='js' />
  </Picker>

This will lead to infinite loop between two items. I have added some debug code when picker receive a onSelect event from native code, and I got those:

 LOG  new onSelect event
 LOG  props.selectedValue is java
 LOG  children[position].props.value is js                <<< Current is java and user select js.
 LOG  new onSelect event                                  <<< The state has changed, and this is triggered when re-render
 LOG  props.selectedValue is js                           <<< Current is now js, that's expected.
 LOG  children[position].props.value is java              <<< Why this become java??? that's expected to be js also.
 LOG  new onSelect event                                  <<< Stating from this line, is infinite state change and infinite loop...
 LOG  props.selectedValue is java
 LOG  children[position].props.value is js
 LOG  new onSelect event
 LOG  props.selectedValue is js
 LOG  children[position].props.value is java
 LOG  new onSelect event
 LOG  props.selectedValue is java
 LOG  children[position].props.value is js
 LOG  new onSelect event
 LOG  props.selectedValue is js
 LOG  children[position].props.value is java
 LOG  new onSelect event
 LOG  props.selectedValue is java
 LOG  children[position].props.value is js
 LOG  new onSelect event
 LOG  props.selectedValue is js
 LOG  children[position].props.value is js
....., infinite output

It seems something conflict with the trigger of onSelect event, the position attribute changes without any user action. (it seem that onSelect will be called when Picker re-rendering, but children[position].props.value get a strange result.)

Platform

Android 11 React Native 0.68.2 recoi 0.5.0 @react-native-picker/picker tested on 2.0.1 and 2.4.1

wtlyu commented 2 years ago

FYI, globalStore in code is a module that holds all recoil atoms. like this:


const selectedLanguage = atom({
  key: 'selectedLanguage',
  default: 'js'
})