无法在异步函数中设置上下文?

kev*_*954 1 reactjs react-native react-context

好吧,请对我温柔一点,我对 React Native 还很陌生,但我正在使用 Context 来管理我的 React Native 项目中的一些状态。这是我陷入困境的一个例子

在功能组件的顶部我有这个......

import DataContext from "../../contexts/DataContext";
import AsyncStorage from "@react-native-community/async-storage";

const AccountHomepageScreen = ({navigation}) => {

     const { data, updateInfo} = useContext(DataContext);


     const getUserFromAsync = async () => {
         try {
             const value = await AsyncStorage.getItem('user_id');
             if(value !== null) {

                 //shows user_id in Alert no problem
                 alert(value);

                 //but this does not work?!?!
                 updateInfo('userId', value);
            
             }
         } catch(e) {
             // error reading value
            return false;
         }
     }
}

useEffect(() => {
    getUserFromAsync();
}, []);
Run Code Online (Sandbox Code Playgroud)

在上下文文件 updateInfo 中执行以下操作

import React, { useState } from 'react';

const DataContext = React.createContext();


export const DataProvider = ({ children }) => {
const [info, setInfo] = useState({
    userId: '',
    textText: 'Connected!!!',
    availableBusinesses : [],
    getBusinessesError: ''
});

const updateInfo = (field, val) => {
    setInfo({
        ...info, [field]: val
    });
};

return (
         <DataContext.Provider value={{
             data: {info},
             updateInfo
         }}>
         {children}
         </DataContext.Provider>
     );

};

export default DataContext;
Run Code Online (Sandbox Code Playgroud)

hac*_*ape 5

const updateInfo = (field, val) => {
    setInfo(info => ({
        ...info, [field]: val
    }));
};
Run Code Online (Sandbox Code Playgroud)

这是一段神奇的代码。尝试一下是否可以解决您的问题;-)


扩展

我在 React 新手中多次看到这种错误。这是典型的过时闭包问题。

SoupdateInfo的闭包捕获info(稍后在 中使用...info),然后getUserFromAsync是闭包捕获updateInfo,最后是useEffect捕获的回调getUserFromAsync

现在因为useEffect的 deplist 是空的,它的回调闭包永远不会更新,它停留在创建的第一个快照上。因此,从创建后的第一次状态更改开始,该闭包将成为陈旧的闭包,也称为“不同步”。

并且由于上面提到的闭包链,从调用点useEffect回调开始,整个链都是停顿的。因此,更新后的info值不会通过setState({ ...info })调用反映出来......

除非您从一开始就避免捕获/快照行为!神奇的代码就是这样做的。它避免通过闭包捕获进行引用info,而是从回调函数参数提供的值中获取该值

setState(info => ...)
Run Code Online (Sandbox Code Playgroud)

虽然封闭链仍然存在stale,但它没有造成真正的损害,因为它没有引用任何外部价值。setState将确保info参数始终设置为最新状态值。