【问题标题】:Unable to read state updated by useReducer hook in context provider无法读取上下文提供程序中的 useReducer 挂钩更新的状态
【发布时间】: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,我如何通过同一函数的最新更改访问状态?

【问题讨论】:

    标签: javascript reactjs react-hooks react-context


    【解决方案1】:

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

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

    1. 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];
    
    1. 您可以在每次状态更改后重置您的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返回的第三个变量吗?是的,您的上下文提供者应该是相同的
    • 啊,对了,我就知道这是微不足道的事情。现在知道了,非常感谢您的回答和所有解释!
    • 真的很高兴你分享这个答案!您的第一个选项确实为我节省了很多时间和精力。谢谢!
    猜你喜欢
    • 2020-09-05
    • 1970-01-01
    • 1970-01-01
    • 2019-09-23
    • 1970-01-01
    • 2021-08-17
    • 1970-01-01
    • 2021-03-02
    • 1970-01-01
    相关资源
    最近更新 更多