无法从 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
标签,我只是想提醒一下,如果你在网络浏览器上预览项目,你的 storedFrequency
在 useEffect
将永远是 null
因为浏览器不支持 AsyncStorage
.
看起来问题出在 Picker 本身以及它如何在每次渲染时调用 onValueChange 而不是仅在更改时调用。我在此线程中找到了一个临时解决方案,直到它得到修复:https://github.com/lawnstarter/react-native-picker-select/issues/112#issuecomment-634038287
我正在使用一个 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
.
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
标签,我只是想提醒一下,如果你在网络浏览器上预览项目,你的 storedFrequency
在 useEffect
将永远是 null
因为浏览器不支持 AsyncStorage
.
看起来问题出在 Picker 本身以及它如何在每次渲染时调用 onValueChange 而不是仅在更改时调用。我在此线程中找到了一个临时解决方案,直到它得到修复:https://github.com/lawnstarter/react-native-picker-select/issues/112#issuecomment-634038287