无法在异步功能中设置上下文?

时间:2020-08-31 01:44:41

标签: 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();
}, []);

在上下文文件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;

2 个答案:

答案 0 :(得分:2)

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

这是一段神奇的代码。尝试解决问题;-)


扩展

我在React新手中多次见到这种错误。这是经典的失效关闭问题。

因此,updateInfo的闭包捕获info(以后在...info中使用),然后getUserFromAsync的闭包捕获updateInfo,最后useEffect的回调捕获getUserFromAsync

现在,由于useEffect的deplist为空,因此其回调关闭永远都不会更新,它停留在有史以来创建的第一个快照上。因此,从创建后的第一个状态更改开始,该关闭将成为过时的关闭,也就是“不同步”。

由于上述闭合链的存在,整个链处于停滞状态,从调用点useEffect回调开始。因此,更新后的info值将不会通过setState({ ...info })调用反映出来……

除非您从一开始就避免捕获/快照行为!魔术代码就是这样做的。它避免通过闭包捕获来引用info,而是从

提供的回调函数param中获取该值。
setState(info => ...)

尽管闭合链仍然是stale,但它没有造成任何实际损害,也没有提及外部价值。 setState将确保info参数始终设置为最新状态值。

答案 1 :(得分:0)

我想您可能正在尝试通过updateInfo函数来更新组件中的某些内容。

在这种情况下,这完全取决于您在哪里调用getUserFromAsync函数。

如果要在加载AccountHomepageScreen后立即调用它,则可以使用hook(请参阅钩子文档here)。

使用useEffect将确保仅当在屏幕上呈现组件时才执行您的代码,因此该功能实际上会影响布局:

import { useContext, useEffect } from 'react'; // Import it where you're already importing useContext
import DataContext from "../../contexts/DataContext";
import AsyncStorage from "@react-native-community/async-storage";

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

  // Calling the hook
  useEffect(() => {
    getUserFromAsync();
  });

  const getUserFromAsync = async () => {
    try {
      const value = await AsyncStorage.getItem("user_id");
      if (value !== null) {
        //shows user_id in Alert no problem
        alert(value);

        // you should be able to call the updateInfo function now
        updateInfo("userId", value);
      }
    } catch (e) {
      // error reading value
      return false;
    }
  };
};