Describe the bug
I seem to be having issues with updating the placeholder after the component is mounted.
To Reproduce
Steps to reproduce the behavior:
Expected behavior
The placeholder should update to the _loading_ placeholder and back to the given placeholder
Smartphone (please complete the following information):
iPad MiniiOS 12.2^6.1.0https://github.com/expo/react-native/archive/sdk-32.0.0.tar.gz16.5.0Reproduction and/or code sample
export default class RNPickerSelect extends PureComponent {
// <snip>
static getDerivedStateFromProps(nextProps, prevState) {
// <snip>
// update selectedItem if value prop is defined and differs from currently selected item
const { selectedItem, idx } = RNPickerSelect.getSelectedItem({
items,
key: nextProps.itemKey,
value: nextProps.value,
});
const selectedItemChanged =
!isEqual(nextProps.value, undefined) && !isEqual(prevState.selectedItem, selectedItem);
console.log(selectedItem, selectedItemChanged) // <-- Logging here
if (itemsChanged || selectedItemChanged) {
if (selectedItemChanged) {
nextProps.onValueChange(selectedItem.value, idx);
}
return {
...(itemsChanged ? { items } : {}),
...(selectedItemChanged ? { selectedItem } : {}),
};
}
return null;
}
// <snip>
}
Object {
"color": "#9EA0A4",
"label": "Select an item...",
"value": null,
} false
Object {
"label": "Loading...",
"value": null,
} false
<Select
{...props}
placeholder={(
this.isLoading(name)
? {
label: 'Loading...',
value: null,
}
: null
)}
disabled={disabled}
value={this.getValue(name)}
items={options}
style={{
inputIOS: newStyle,
inputAndroid: newStyle,
}}
onValueChange={text => call([this.onChange, onChange], { field, text })}
/>
After investigating the issue it seems to be down to the input not having a string value. But once the placeholder updates (value of null) then it fires an onValueChange that then clears the string value.
I think there should be a prop or similar to disable resetting of the value if the new selected item's value is null.
Why not just have the ternary switch between an empty string and “Loading”?
On mobile and just taking a quick glance at this - so I may have missed something.
Why not just have the ternary switch between an empty string and “Loading”?
I wasn't aware that it should just be a string? I assume it'd still have the same issue though.
The placeholder prop expects an empty object or an object in the proper format. You’re passing in null instead - not sure how that’s going to react.
The placeholder prop expects an empty object or an object in the proper format. You’re passing in null instead - not sure how that’s going to react.
Interesting. I'm passing in the value null as seen by the default placeholder. I can change that.
i mean
placeholder="{}"
or
placeholder="{ label: '', value: null }"
are correct.
placeholder="null"
^ this may break something. Also - can you fill out the entire bug report? You left off the versions.
placeholder="null"
The placeholder of _null_ becomes placeholder={null} which I assume is the same as not passing anything. As mentioned the _null_ is just to show that there's no pointers between the changing placeholder.
placeholder="{ label: '', value: null }"
This is what is currently being done.
I'll update the report to include versions.
{
"main": "node_modules/expo/AppEntry.js",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"eject": "expo eject",
"postinstall": "node ./quiet-console.js"
},
"dependencies": {
"@expo/vector-icons": "latest",
"@ninetynine/call": "^1.1.0",
"@ninetynine/noop": "^1.1.1",
"expo": "^32.0.0",
"lodash": "^4.17.11",
"prop-types": "latest",
"react": "16.5.0",
"react-native": "https://github.com/expo/react-native/archive/sdk-32.0.0.tar.gz",
"react-native-datepicker": "^1.7.2",
"react-native-picker-select": "^6.1.0",
"react-navigation": "^3.11.0",
"react-navigation-header-buttons": "^2.3.1",
"sentry-expo": "^1.12.0"
},
"devDependencies": {
"babel-preset-expo": "^5.0.0"
},
"private": true
}
Seemingly setting placeholder as a string crashes the app.
placeholder="Text"
I’m sure it does - it expects an object.
So the ternary of “Loading” to “” didn’t work?
I'll look into this and get back to you
Related to #112 - placeholder won't update because it's the currently selected value and selectedItemChanged doesn't fire in this instance. Would be fixed if this is made into a controlled component - or could potentially be specialcased.
Warning: value prop on select should not be null. Consider using an empty string to clear the component or undefined for uncontrolled components.
Set the placeholder like this
placeholder={
{ label: 'Select Gender', value: null, color: '#909090', }
}
It works for me.
Same bug here
When i reset the select it still remember the old value:
<RNPickerSelect
key="csp"
onValueChange={(value): void => SetSalePointsFilter({ key: 'csp', value })}
Icon={(): React.ReactNode => <Unicons name="angle-down" size={22} />}
useNativeAndroidPickerStyle={false}
placeholder={{
label: 'CSP',
value: null,
...styles.placeholderColor,
}}
value={listing.filters.csp}
style={styles.select}
items={items.csp}
/>
Same bug here
When i reset the select it still remember the old value:<RNPickerSelect key="csp" onValueChange={(value): void => SetSalePointsFilter({ key: 'csp', value })} Icon={(): React.ReactNode => <Unicons name="angle-down" size={22} />} useNativeAndroidPickerStyle={false} placeholder={{ label: 'CSP', value: null, ...styles.placeholderColor, }} value={listing.filters.csp} style={styles.select} items={items.csp} />
Ok, it works for me.
To reset the select, set the component value to null and the value of placeholder also null
<RNPickerSelect
key="csp"
onValueChange={(value): void => SetSalePointsFilter({ key: 'csp', value: value || null })}
Icon={(): React.ReactNode => <Unicons name="angle-down" size={22} />}
useNativeAndroidPickerStyle={false}
placeholder={{
label: 'CSP',
value: null,
...styles.placeholderColor,
}}
value={listing.filters.csp}
style={styles.select}
items={items.csp}
/>
In my case, placeholder was not getting updated if it is based on state, I solved this using a hack.
In index.js file of the react-native-picker-select
Change following line
const selectedItemChanged =
!isEqual(nextProps.value, undefined) && !isEqual(prevState.selectedItem, selectedItem);
to
const selectedItemChanged =
!isEqual(nextProps.value, undefined) || !isEqual(prevState.selectedItem, selectedItem)
|| prevState.selectedItem.valued != selectedItem.value
;
Its a hack but it works.
Most helpful comment
Set the placeholder like this
It works for me.