从 useState 中的异步函数获取值
Posted
技术标签:
【中文标题】从 useState 中的异步函数获取值【英文标题】:get value from async function in useState 【发布时间】:2021-11-24 10:04:29 【问题描述】:我正在使用async storage 来检索我的数据,但如何将它与 useState() 一起使用?
例子:
async function getdata()
let d= await AsyncStorage.getItem('Name');
return d;
export default function App()
const [name, setName] = useState(() => getdata());
return (<View>...</View>)
但这不起作用,因为 getdata() 是异步的,那么我该如何解决这个问题?
编辑:
我忘了说我试过 useEffect() Hook 是这样的:
async function getdata()
let d= await AsyncStorage.getItem('Name');
console.log('retrieved Data!');
return d;
const [name, setName] = useState(()=>0);
useEffect(() =>
getData().then(setName);
console.log('moving on...');
, []);
但执行顺序是:
“继续……” '检索数据!'
应该是相反的地方
【问题讨论】:
响应编辑,'moving on'首先解析的原因是因为getData是一个异步函数。这意味着程序在移动到下一行之前不会等待 getData 完成执行。这可以。这只是意味着组件将在没有设置名称的情况下“渲染”一次,然后在调用 setName 时再次重新渲染,此时“名称”变量将填充来自 asyncstorage 的任何内容。在这种情况下,不需要在 useState() 中放置回调函数。将其初始化为一些文字就可以了。 【参考方案1】:您会将您的状态初始化为某个空值。也许是一个空字符串,也许是一个空值。如果你愿意,你可以让你的组件在这段时间内渲染一些不同的东西,比如加载指示器。然后一旦数据加载,你可以设置状态再次渲染。
export default function App()
const [name, setName] = useState(null);
useEffect(() =>
getData().then(value => setName(value));
, []);
if (name === null)
return <Text>Loading...</Text>
else
return (<View>...</View>)
【讨论】:
getData().then(setName);
:)
真的很抱歉我忘了说我试过这个但我仍然没有得到想要的效果,你可以在问题的编辑中看到
@cakelover 您的编辑显示getData().then(setName(value));
,这是错误的。它立即设置状态,并将结果传递给.then
。将其更改为 getData().then(value => setName(value));
或 getData().then(setName);
哦,我真的很抱歉我在我的实际代码中写了getData().then(setName);
,我在编辑时不小心写错了,我现在修好了【参考方案2】:
你必须使用useEffect
export default function App()
const [name, setName] = useState('');
useEffect(() =>
const bootstrap = async () =>
const name = await getdata();
setName(name);
;
bootstrap();
, []);
return <View>...</View>;
【讨论】:
我尝试了这种方法,但它没有给出想要的结果,很抱歉我忘记在问题中提及它,我现在已经进行了编辑 @cakelover 有什么问题? 执行顺序,你可以在下面的编辑中看到我提到它应该是相反的方式,即 getdata 然后继续【参考方案3】:我认为这里最好的解决方案是将 name 初始化为 false,然后在 .then() 回调中使用 'setName'。 setName(以及那些通常来自 useState 的 setter 函数)旨在作为一种异步更新该值的方式。
我在这里将名称设置为布尔值“假”并严格检查。如果存在该名称字段为空的情况,则可以将其设置为空字符串而不会导致无限循环。
async function getdata()
let d= await AsyncStorage.getItem('Name');
return d;
export default function App()
const [name, setName] = useState(false);
useEffect(() =>
if (name === false)
getData().then((name) =>
setName(name);
);
, []);
return (<View>...</View>)
请记住,您的视图必须能够处理错误的名称值。如何做到这一点取决于您。
^^^上述解决方案应该可以有效地解决您的问题,但我会在这里快速说明:如果您的组件相对复杂,它可能会由于其他原因重新渲染多次,因此会运行 if( name === false) 条件,因为它等待回调解决。这不会破坏事情,但它会对异步存储造成不必要的影响,并可能影响性能。如果您发现是这种情况,请使用下面的有用文章查看“去抖动”回调。 https://medium.com/@gabrielmickey28/using-debounce-with-react-components-f988c28f52c1
【讨论】:
不好意思我有点慢,我还是不明白if (name === false)
的用法是什么?因为我们事先将它初始化为假,所以它不总是真的吗?您是否建议将其作为缓冲区,例如在获取值时添加“加载”文本?
它允许您避免在每次重新渲染时从异步存储重新加载名称,因为“false”实际上是一个表示“尚未加载”的标志。在最初从存储中获取名称后,它会被拉入您的组件中,不需要再次获取。
我不确定,但 useState(()=>false)
不能避免每次都渲染吗?
useState 仅在第一次渲染时初始化值。随后的渲染周期,例如当 getData 的回调解决时由 setName 触发的渲染周期,不会将“名称”重新初始化为 false。以上是关于从 useState 中的异步函数获取值的主要内容,如果未能解决你的问题,请参考以下文章