【问题标题】:Can't set Context in async function?不能在异步函数中设置上下文?
【发布时间】:2020-08-31 01:44:41
【问题描述】:

好吧,请对我温柔一点,我对 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;

【问题讨论】:

  • //but this does not work?!?! 你能说得更具体点吗?你期待发生什么?您可能需要向我们展示 updateInfo 的代码是什么。
  • 我实际上是在 useEffect 中调用它,我只是忘了包括它。抱歉,是的,我正在尝试使用 userID 值设置上下文
  • 我也添加了DataContext文件
  • 谢谢。发生了什么问题?您是否在组件主体中粘贴了日志语句(不是在使用效果或 getUserFromAsync 中)并且它没有重新渲染?
  • 上下文不会随值更新。该值在那里,因为它显示在警报中。我只是不明白为什么上下文没有随脚本更新。它适用于其他任何地方。我只能假设它与调用它的异步函数有关

标签: reactjs react-native react-context


【解决方案1】:
const updateInfo = (field, val) => {
    setInfo(info => ({
        ...info, [field]: val
    }));
};

这是一段神奇的代码。试试它是否能解决你的问题;-)


扩展

我在 React 新手中多次看到这种错误。这是经典的陈旧关闭问题。

所以updateInfo的闭包捕获info(后面用...info),然后getUserFromAsync的闭包捕获updateInfo,最后useEffect的回调捕获getUserFromAsync .

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

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

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

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

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

【讨论】:

  • 这解释了为什么它在更新 useEffect 之外的一些值时起作用。再次感谢您的帮助和详细解释为什么它永远不会起作用。这些整天与问题作斗争肯定会让我做得更好。在像你这样的专业人士的帮助下,我肯定会这样学得最好。非常感谢!
【解决方案2】:

我猜您可能正在尝试通过 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;
    }
  };
};

【讨论】:

  • 感谢 rleiva93,我感谢您的努力,但那是我已经使用过的,应该全部发布。对此感到抱歉。我不想使用 redux 作为状态管理工具,但可能需要研究一下。我只是不明白为什么在 getUserFromAsync 之前的警报具有正确的值时,上下文不会在 getUserFromAsync 内部得到更新。再次感谢您的尝试
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-07-27
  • 2018-08-20
  • 2019-02-27
  • 1970-01-01
  • 2022-07-07
  • 2020-10-25
  • 2022-10-04
相关资源
最近更新 更多