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
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,
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:
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.
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
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}
/>