无法从 React Native 中的异步存储更新 Picker 组件

Trouble updating Picker component from Async Storage in React Native

我正在使用一个 Picker 组件让用户设置一个值,以决定他们想要提醒某事的频率。在下面的代码中,我将结果保存在组件的状态中,并使用异步存储将其保存到设备中:

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>

我还想让组件获取保存的数据并将其设置为首次渲染时的状态。

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

基于我对异步存储的有限了解,这似乎是有道理的。我觉得是

但是,这不起作用。如果我离开然后返回页面,则状态已重置。

更新:

如果我 console.log onValueChange 异步函数中的 itemValue 这就是我得到的:

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

将值更改为 'never' 时,它会打印

never 
never

当我离开然后返回时,甚至没有触及组件,它打印出:

week
week
never
never
year
year

year
never
year
year

或其他一些长串值,表明某处存在反馈循环。

您的表达式 AsyncStorage.setItem() 没有触发,因为您忘记在 onValueChange.

的回调函数中调用 Self-Invoking 函数
    onValueChange={(itemValue, itemIndex) => { 
        (async () => { 
            await AsyncStorage.setItem(`@circle_${circle.name}_frequency`, itemValue)
        })(); // I will invoke myself
        setFrequency(itemValue);
    }}

更新(根据更新的问题):

我没有在您给定的片段代码中发现更多错误,而且我不知道您的完整源代码发生了什么。无论如何,我已经创建了一个超级简单的工作片段代码,后面是您问题中的代码,因此您可以直接复制到您的项目中。

import React, {useState, useEffect} from 'react';
import {Picker, AsyncStorage} from 'react-native';

export default function App() {
  const [frequency, setFrequency] = useState('year');
  useEffect(() => {
    const fetchFrequency = async () => {
      let storedFrequency = await AsyncStorage.getItem('@circle_circle_name_frequency');
      if (storedFrequency != null) {
        setFrequency(storedFrequency);
      }
    };
    fetchFrequency();
  }, []);

  return (
    <Picker
      selectedValue={frequency}
      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" />
    </Picker>
  );
}

希望对您有所帮助!

PS:我看到你在你的问题上加上了 expo 标签,我只是想提醒一下,如果你在网络浏览器上预览项目,你的 storedFrequencyuseEffect 将永远是 null 因为浏览器不支持 AsyncStorage.

看起来问题出在 Picker 本身以及它如何在每次渲染时调用 onValueChange 而不是仅在更改时调用。我在此线程中找到了一个临时解决方案,直到它得到修复:https://github.com/lawnstarter/react-native-picker-select/issues/112#issuecomment-634038287