【问题标题】:how to use the useEffect hook to initialize reducerstate如何使用 useEffect hook 来初始化 reducerstate
【发布时间】:2021-08-23 12:46:01
【问题描述】:

所以我的问题是我想使用一个函数来生成我的初始状态,然后在我的减速器中使用该生成的状态。

我的 App 组件函数之外有这个 StateGenerator() 函数,它返回一个大数组。

如果我这样写:

const [boardState, tileDispatchFn] = useReducer(
    tileReducer,
    StateGenerator()
  );

它可以工作,但是 StateGenerator() 函数在每次渲染时都会执行(这正常吗??)尽管状态没有重置为初始状态(我猜这很好??)

但是每次渲染都会执行这些函数,并且它会生成一个相当大的数组,如果我通过点击它来快速渲染就会中断

如果我这样写:

let initState = null;

useEffect(() => {
    initState = StateGenerator();
  }, []);

  const [boardState, tileDispatchFn] = useReducer(
    tileReducer,
    initState
  );

我收到这样的错误 Cannot read property ... of null 因为 useEffect 是在渲染之后执行的

使用我的 StateGenerator() 函数生成初始状态的最简单方法是什么?最好的方法是什么?

【问题讨论】:

    标签: reactjs react-hooks


    【解决方案1】:

    我认为最简单的方法是使用 useReducer 的第三个参数,这是一个初始化函数。

    useReducer - const [state, dispatch] = useReducer(reducer, initialArg, init);

    Lazy initialization

    您也可以懒惰地创建初始状态。为此,您可以通过 init 函数作为第三个参数。初始状态将被设置 到init(initialArg)

    它可以让你提取计算初始状态的逻辑 在减速器之外。

    我不知道你的状态是什么样的,但这就是它的使用方式。

    const [boardState, tileDispatchFn] = useReducer(
      tileReducer,
      {              // <-- default initial board state
        // state keys with safe default values
      },
      StateGenerator // <-- state initializer function
    );
    

    【讨论】:

    • 感谢您的回复,此解决方案可以避免每次渲染都执行“生成器”功能,但我仍然需要一些初始状态。我让它在几乎为空的初始状态下工作(通过在代码中添加大量的空检查),但现在还可以。
    • @xvk 正确,这是“默认初始板状态”的一部分。您可以提供不会在 UI 中引发错误的初始状态(即空数组 [] 或字符串 ''),或者在 UI 中实现空值检查(或在以下情况下两者结合)糟糕的状态更新)。
    【解决方案2】:

    您可以调度一个设置减速器初始状态的操作。当组件挂载时,您可以调度操作以从任何组件设置状态,例如:

    import React from "react";
    const initialState = { count: 0 };
    
    function reducer(state, action) {
      switch (action.type) {
        case "set_initial":
          return { count: action.payload };
        case "increment":
          return { count: state.count + 1 };
        case "decrement":
          return { count: state.count - 1 };
        default:
          throw new Error();
      }
    }
    
    export default function App() {
      const [state, dispatch] = React.useReducer(reducer, initialState);
      React.useEffect(() => {
        dispatch({ type: "set_initial", payload: 10 });
      }, []);
      return (
        <>
          Count: {state.count}
          <button onClick={() => dispatch({ type: "decrement" })}>-</button>
          <button onClick={() => dispatch({ type: "increment" })}>+</button>
        </>
      );
    }
    

    【讨论】:

    • 感谢您的回复,唯一的问题是我仍然需要“硬编码”一个初始状态。在 useEffect 中使用 dispatch 函数比我的解决方案要好,但我认为 @Drew 的解决方案更干净,因为它本质上做同样的事情,但使用 init 函数并且不需要 useEffect 钩子。不过,在他的解决方案中,我还需要某种“硬编码”初始状态。
    猜你喜欢
    • 2023-04-06
    • 2011-03-14
    • 2017-03-24
    • 1970-01-01
    • 2020-02-13
    • 2020-09-26
    • 2021-05-26
    • 1970-01-01
    • 2021-03-11
    相关资源
    最近更新 更多