React-native-picker-select: Cannot update component inside function

Created on 10 Aug 2020  ·  22Comments  ·  Source: lawnstarter/react-native-picker-select

I have a standard Picker with Hooks updating the component.

The hook is updated in a useeffect, the initial component is set waiting on the useeffect and then hits this warning. If I stick to RNC/Picker

                        <RNPickerSelect
                            onValueChange={(value) => handleStuff(value)}
                            placeholder={{ label: 'Select Stuff' }}
                            value={gStuff}
                            style={pickerSelectStyles}
                            pickerProps={styles.rnPickerProps}
                            useNativeAndroidPickerStyle={false}
                            items={Stuff} />
                    </View>

Describe the bug

Cannot Update a component from inside the function body of a different component.

Again, a very standard picker. Set a useState, update and show component. This is a new warning which is concerning. I thought hooks were supposed to work this way.

Additional details

  • Android Moto G6
  • OS: Android
  • react-native-picker-select version: 8.0
  • react-native version: latest
  • expo sdk version: none

Most helpful comment

For everyone on this thread, I had this issue and fixed it by following someone's suggestion of adding key to the Picker. That solved the problem for me, all is working great. I used the value from list which is unique. See below:
key={gStuffID}
onValueChange={value => handleSelectStuff(value)}
placeholder={{ label: 'Select Stuff' }}
items={gStuffList}
style={pickerSelectStyles}
pickerProps={styles.rnPickerProps}
useNativeAndroidPickerStyle={false}
value={gStuffID}
/>

All 22 comments

Intially gStuff is a default value (not from handleStuff). I get the error then. How else would I update the default and updated selected value to display?
I don't understand the issue,

  1. Get data from table (10 options or so)
  2. Set default value
  3. Update hook as user selects

THe handlestuff is straight forward:
const handleStuff = (value) => {
setGStuff(value);
};

What am I doing wrong? I don't see it.

I'm having a similar problem with this picker:

<RNPickerSelect
          onValueChange={(newPerson) => {
            setFieldValue('person', newPerson);
          }}
          items={personPickerItemsThatWillChange}
          value={values.person}
        />

I get this error when the items I pass to the picker change based on the values selected in the other pickers in the form.

 ERROR    Warning: Cannot update a component from inside the function body of a different component.
    in RNPickerSelect (at MyModal.tsx:189)
    in RCTView (at View.js:34)
    in View (at MyModal.tsx:396)
    in RCTView (at View.js:34)
    in View (at MyModal.tsx:299)
    in Formik (at MyModal.tsx:278)
    in RCTScrollContentView (at ScrollView.js:1124)
    in RCTScrollView (at ScrollView.js:1260)
    in ScrollView (at ScrollView.js:1286)
   ...

According to this issue regarding this error, the child component (the picker) cannot do something like this:

function Child({ setState }) {
  setState(true);

  return <h1>This is a child.</h1>;
}

function Parent() {
  const [state, setState] = useState(false);

  return <Child setState={setState} />;
}

but should do this instead:

function Child({ setState }) {
  useEffect(() => {
    setState(true);
  }, [setState]);
  return <h1>This is a child.</h1>;
}

For everyone on this thread, I had this issue and fixed it by following someone's suggestion of adding key to the Picker. That solved the problem for me, all is working great. I used the value from list which is unique. See below:
key={gStuffID}
onValueChange={value => handleSelectStuff(value)}
placeholder={{ label: 'Select Stuff' }}
items={gStuffList}
style={pickerSelectStyles}
pickerProps={styles.rnPickerProps}
useNativeAndroidPickerStyle={false}
value={gStuffID}
/>

@dl-husky73 adding the key didn't fix the error for me :( Do you mind going into a little more detail on how you're updating gStuffList ?

I'm having the same error with the following setup:

const bandOptions = () => {
    return bands.map((band) => {
      return {
        label: band.name,
        value: band.id,
        key: band.id
      }
    })
  }

  return (
    <RNPickerSelect
      key={key}
      placeholder={{
        label: placeholder ?? 'Select the corresponding band',
        value: null
      }}
      style={{inputIOS: styles.input}}
      onValueChange={(value) => onChange(value)}
      items={bandOptions()}
      useNativeDriver={false}
      value={defaultValue}
    />
  )

Weird. I had the same issue, read about the key and made it my ID. Oh one thing, I set a default ID so it is 0 not null. Here is handleSelectStuff, I tried the useeffect approach but went back to calling the function to update API call. My handlestuff looks like this. The picker select info is the first few lines, if changed I check an external API to get updated info (non related)

const handleSelectStuff = (value) => {
    if (value && gStuffID === value) {
        return;
    } else {
        setStuffID(value);
    }
    gStuff.map((item) => {
        if (item.value === value) {
           .....update stuff....
           .....make API call for 3rd party info....
                  var url = "apicall"
                fetch(url)
                    .then(response => response.json())
                    .then((responseJSON) => {
                        if (responseJSON.sites) {
                            gOtherStuff.stuff = responseJSON.sites[0];
                        }
                    })
                    .catch(error => console.log(error)) //to catch the errors if any
            } else {
                gOtherStuff.stuff = null;
            }
        }
    });
};

I had the same issue and solved it by adding a key prop like @dl-husky73 said.
Along with this error, the initial value was not being set for me and adding the key prop also solved this.
I used the same value that I used for the value prop for the key prop.

<RNPickerSelect
  key={selectedValue}
  onValueChange={(val) => setSelectedValue(val)}
  placeholder={{label: 'Choose one', value: null}}
  value={selectedValue}
  items={pickerItems}
  style={pickerSelectStyles}
/>

Right, I figured it out. Makes sense now.

What I was doing wrong is that I was putting the in a defaultValue without using state 🤦🏼‍♂️
So i just put in a static int (1) in the value and key props. I guess I thought that the value prop was just for setting the default prop, but instead you need to update both of these props to match the selected option.

So if anyone else makes the same stupid move as I did, this should work:

const [value, setValue] = useState(defaultValue)

const selectItem = (newValue) => {
  setValue(newValue)
  // custom stuff here
}

....


<RNPickerSelect
  key={value}
  placeholder={{label: 'Choose an item', value: null}}
  onValueChange={(newValue) => selectItem(newValue)}
  items={bandOptions()}
  useNativeDriver={true}
  value={value}
/>

try this.

onValueChange={(value) =>
value !== gStuff && handleStuff(value)
}
placeholder={{ label: 'Select Stuff' }}
value={gStuff}
style={pickerSelectStyles}
pickerProps={styles.rnPickerProps}
useNativeAndroidPickerStyle={false}
items={Stuff} />

Nothing works for me from above

Adding the key works for me, but it had to be a unique value, e.g. the data used in the value prop. Didn't work with a predefined string passed down to the key prop.

For me, although setting the key to the id makes the iOS drawer immediately shut when something is selected, without clicking done.

Same for me. The drawer closes after selecting an element, and the onClose method it's never being executed. Any updates on this issue?

please check if #368 fixes this

Is there any update on issue: iOS drawer immediately shut when something is selected without clicking done? Mentioned https://github.com/lawnstarter/react-native-picker-select/pull/368 is blocked as I can see.

Thanks

@milennaj based on your thumbsdown, #368 did not fix the issue for you?

@milennaj based on your thumbsdown, #368 did not fix the issue for you?

My mistake, it does fix the issue, but my question was more when can we expect this to be released? Great job @lfkwtz

same issue

@kbwo solution makes some sense. It looks like the picker calls unnecessary renderings. So if you prevent it with:
onValueChange={(newValue) => newValue !== state && setState(newValue)}
Warning will be gone.

Does #368 fix the "Cannot update a component from inside the function body of a different component." warning? And is there going to be a new version soon that includes this fix? I've tried all the suggestions in this thread and nothing works for me so far to clear this warning.

For my temporary solution (just for references)
in react-native-picker-select/src/index.js,
remove line 131 inside function getDerivedStateFromProps:

    if (itemsChanged || selectedItemChanged) {
        if (selectedItemChanged) {
            nextProps.onValueChange(selectedItem.value, idx); //remove this line
        }

        return {
            ...(itemsChanged ? { items } : {}),
            ...(selectedItemChanged ? { selectedItem } : {}),
        };
    }

This is to avoid the update of "selectedItem" state inside the component when "value" props is updated through "onValueChange" since there is already a state update for "selectedItem" in line 186 function onValueChange

"selectedItem" is the state used within this picker-select component;
"value" props is the string value controlled by us;

fixed in v8.0.3

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dkniffin picture dkniffin  ·  3Comments

dquessenberry picture dquessenberry  ·  7Comments

gregogalante picture gregogalante  ·  4Comments

sebqq picture sebqq  ·  9Comments

luizParreira picture luizParreira  ·  8Comments