Search code examples
react-nativeexpoasyncstorage

Trouble updating Picker component from Async Storage in React Native


I'm using a Picker component to let the user set a value for how frequently they want to be reminded about something. In the code below, I'm saving the result in the component's state as well as saving it to the device with Async Storage:

const [frequency, setFrequency] = useState('year');

...

<Picker
    selectedValue={frequency}
    style={styles.picker}
    itemStyle={styles.pickerItem}
    onValueChange={(itemValue, itemIndex) => { 
        (async () => { 
            await AsyncStorage.setItem(`@circle_${circle.name}_frequency`, itemValue)
        })();
        setFrequency(itemValue);
    }}
    mode={'dropdown'}
    prompt={'Reminder every:'}
>
    <Picker.Item label="Never" value="never" />
    <Picker.Item label="Day" value="day" />
    <Picker.Item label="Week" value="week" />
    <Picker.Item label="Year" value="year" />
    etc...
</Picker>

I'd also like to have the component grab the saved data and set that as the state when first rendering.

    useEffect(() => {
        const fetchFrequency = async () => {
            let storedFrequency =  await AsyncStorage.getItem(`@circle_${circle.name}_frequency`);
            if (storedFrequency != null) { 
                setFrequency(storedFrequency);
            };
        }
        fetchFrequency();
    }, []);

Based on the limited amount I know about Async Storage, this seems to make sense. I think it's

  • awaiting the result of grabbing the value from storage
  • setting the state
  • rendering the component (this could be happening before setting state as well, but I figure it would render again when the state changes)
  • updating both storage and state when the user chooses a new option

However, this doesn't work. If I navigate away and then back to the page, the state has been reset.

UPDATE:

If I console.log the itemValue in the onValueChange async function this is what I get:

onValueChange={(itemValue, itemIndex) => { 
                        (async () => { 
                            await AsyncStorage.setItem(`@circle_${circle.name}_frequency`, itemValue)
                            console.log(itemValue)
                        })();
                        setFrequency(itemValue);
                    }}

When changing the value to 'never', it prints

never 
never

When I navigate away and then come back, without even touching the compnent it prints out:

week
week
never
never
year
year

or

year
never
year
year

or some other long string of values which shows that there's a feedback loop going on somewhere.


Solution

  • It looks like the problem was an issue with the Picker itself and how it calls onValueChange every render rather than only when changed. I found a temporary solution in this thread for until it gets fixed: https://github.com/lawnstarter/react-native-picker-select/issues/112#issuecomment-634038287