无法读取上下文提供程序中的 useReducer 挂钩更新的状态

Posted

技术标签:

【中文标题】无法读取上下文提供程序中的 useReducer 挂钩更新的状态【英文标题】:Unable to read state updated by useReducer hook in context provider 【发布时间】:2019-08-23 22:21:07 【问题描述】:

我正在使用 useReducer 挂钩来管理我的状态,但我在上下文提供程序中读取更新状态时似乎遇到了问题。

我的上下文提供者负责获取一些远程数据并根据响应更新状态:

import React,  useEffect  from 'react';
import useAppState from './useAppState';


export const AppContext = React.createContext();

const AppContextProvider = props => 
  const [state, dispatch] = useAppState();

  const initialFunction = () => 
    fetch('/some_path')
      .then(res => 
        dispatch( type: 'UPDATE_STATE', res );
      );
  ;

  const otherFunction = () => 
    fetch('/other_path')
      .then(res => 
        // why is `state.stateUpdated` here still 'false'????
        dispatch( type: 'DO_SOMETHING_ELSE', res );
      );
    
  ;

  const actions =  initialFunction, otherFunction ;

  useEffect(() => 
    initialFunction();
    setInterval(otherFunction, 30000);
  , []);

  return (
    <AppContext.Provider value= state, actions >
      props.children
    </AppContext.Provider>
  )
;

export default AppContextProvider;

useAppState.js 很简单:

import  useReducer  from 'react';


const useAppState = () => 
  const reducer = (state, action) => 
    switch (action.type) 
      case 'UPDATE_STATE':
        return 
          ...state,
          stateUpdated: true,
        ;
      case 'DO_SOMETHING_ELSE':
        return 
          ...state,
          // whatever else
        ;
      default:
        throw new Error();
    
  ;


  const initialState =  stateUpdated: false ;

  return useReducer(reducer, initialState);
;


export default useAppState;

问题是,如上面的评论所述,为什么上下文提供者的otherFunction 中的state.stateUpdated 仍然是false,我如何通过同一函数的最新更改访问状态?

【问题讨论】:

【参考方案1】:

state 在该函数中永远不会改变

state 在该函数中永远不会改变的原因是state 仅在重新渲染时更新。因此,如果您想访问state,您有两种选择:

    useRef 以查看 state 的未来值(您必须修改减速器才能使其工作)
const updatedState = useRef(initialState);
const reducer = (state, action) => 
  let result;
  // Do your switch but don't return, just modify result

  updatedState.current = result;
  return result;
;

return [...useReducer(reducer, initialState), updatedState];
    您可以在每次状态更改后重置您的setInterval,以便它可以看到最新的状态。但是,这意味着您的间隔可能会被打断很多。
const otherFunction = useCallback(() => 
  fetch('/other_path')
    .then(res => 
      // why is `state.stateUpdated` here still 'false'????
      dispatch( type: 'DO_SOMETHING_ELSE', res );
    );
  
, [state.stateUpdated]);

useEffect(() => 
  const id = setInterval(otherFunction, 30000);
  return () => clearInterval(id);
, [otherFunction]);

【讨论】:

@errata 如果答案对您有用,请不要忘记将其标记为答案。 嘿,抱歉,之前没有机会尝试这个。我采用了第一种方法,在我的用例中似乎更容易实现,但是,我仍然没有在我的示例中看到 otherFunction() 范围内的更新状态,但我确实看到它超出了它的范围。我不得不承认我不太明白为什么会这样,你呢?我应该在我的上下文提供程序中以同样的方式使用useAppState(),对吧? 你使用了updatedStateuseAppState返回的第三个变量吗?是的,您的上下文提供者应该是相同的 啊,对了,我就知道这是微不足道的事情。现在知道了,非常感谢您的回答和所有解释! 真的很高兴你分享这个答案!您的第一个选项确实为我节省了很多时间和精力。谢谢!

以上是关于无法读取上下文提供程序中的 useReducer 挂钩更新的状态的主要内容,如果未能解决你的问题,请参考以下文章

在 React 中使用 useContext 和 useReducer 创建新的键值对

如何测试组件中的react useContext useReducer调度

使用 useContext useReducer 基本示例反应登录

上下文 + Hooks 或 Redux

反应上下文重新渲染提供者的每个孩子?

如何为以下 contextapi 代码的 useReducer useContext 设置 Typescript 类型?