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

问题描述

我正在使用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();
    },[]);

基于我对异步存储了解的有限数量,这似乎是有道理的。我认为是

  • 等待从存储中获取价值的结果
  • 设置状态
  • 渲染组件(这也可能在设置状态之前发生,但是我认为在状态更改时会再次渲染)
  • 用户选择新选项时更新存储和状态

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

更新:

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

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

将值更改为“从不”时,它会打印

never 
never

当我导航离开然后返回时,甚至不触摸组件就会打印出来:

week
week
never
never
year
year

year
never
year
year

或其他一些长字符串,表明某处正在进行反馈循环。

解决方法

您的表达式AsyncStorage.setItem()未触发,因为您忘记了在onValueChange的回调函数中调用自调用函数。

    onValueChange={(itemValue,itemIndex) => { 
        (async () => { 
            await AsyncStorage.setItem(`@circle_${circle.name}_frequency`,itemValue)
        })(); // I will invoke myself
        setFrequency(itemValue);
    }}

已更新(在更新后的问题之后):

在您指定的代码段中,我再也没有发现任何bug,也不知道完整的源代码是怎么回事。无论如何,我创建了一个超级简单的工作片段代码,后面是您问题中的代码,因此您只需将其复制到您的项目中即可。

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标记,我想提醒一下,如果您在网络浏览器上预览项目,则storedFrequency中的useEffect将始终是null,因为浏览器不支持AsyncStorage

,

问题似乎出在Picker本身及其如何在每个渲染上调用onValueChange而不是仅在更改时出现问题。我在此线程中找到了一个临时解决方案,直到它解决为止:https://github.com/lawnstarter/react-native-picker-select/issues/112#issuecomment-634038287