【问题标题】:Is it possible to change state without dispatch in useReducer?是否可以在不调度 useReducer 的情况下更改状态?
【发布时间】:2021-12-30 07:34:02
【问题描述】:

我发现控制台中的 state.elements 已更改,即使我还没有发送。 是什么原因?

const initialState = { elements: [['apple','banana'],['rabbit','cat']] };

function reducer(state, action) {
  switch (action.type) {
    case "increment":
      return { count: state.count + 1 };
    case "decrement":
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = React.useReducer(reducer, initialState);
    
  const changeList=()=>{
    const elementsArray = Array.from(state.elements);
    elementsArray[0][0]='Tiger'
  }

  return (
    <>
      Count: {state.elements}
      <button onClick={changeList}>Change List without dispatch</button>
    </>
  );
}

【问题讨论】:

  • 是的,elementsArray[0][0]='Tiger' 是一个状态突变。您应该向useReducer 钩子发送一个操作以更新状态中的 that 元素。这似乎是一个非常人为的代码示例,但您真正想要做什么?或者如果可以改变状态,你的帖子真的像 YES|NO 一样简单吗?
  • 我将复杂的代码简化为发布堆栈流。我在没有调度的情况下多次按下按钮,我看到即使我没有调度元素也发生了变化,并且它也呈现在屏幕上。
  • 这是我github中的原始代码。 github.com/piaojing/react-zero/commit/…

标签: javascript react-hooks use-reducer


【解决方案1】:

是的,可以在 useReducer 中不分派而更改状态。

就像 React 中的任何状态一样,它可以被改变。 useReducer 状态也不例外。

const changeList=()=>{
  const elementsArray = Array.from(state.elements);
  elementsArray[0][0] = 'Tiger'; // <-- state mutation
}

通过引用复制数组,因此即使elementsArraystate.elements 数组的副本,数组元素仍然是对仍在state.elements 中的原始元素的引用。将elementsArray[0][0] 设置为"Tiger" 与将state.elements[0][0] 设置为"Tiger" 具有相同的效果。

React 中的突变是一种巨大的禁忌,一种反模式。你尤其不要改变状态或道具。状态和道具将被视为不可变对象。这就是为什么状态更新总是需要创建新的对象引用

一个不可变的更新示例:

在这里,您可以浅拷贝每个正在更新的状态深度级别。用于浅拷贝对象属性的 Spread 语法,以及用于将数组元素浅拷贝到新数组中的 Array.prototype.map

function reducer(state, action) {
  switch (action.type) {
    case "update_animal":
      const { index1, index2, value } = action.payload;
      return {
        ...state,
        elements: state.elements.map((outerEl, indexOuter) => 
          indexOuter === index1
            ? outerEl.map((innerEl, indexInner) => 
              indexInner === index2 ? value : innerEl
            )
            : outerEl
        )
      };

    ... other cases ...

    default:
      return state;
  }
}

...

dispatch({
  type: "update_animal",
  payload: {
    index1: 0,
    index2: 0,
    value: "Tiger",
  }
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-23
    • 2013-10-29
    • 1970-01-01
    • 1970-01-01
    • 2017-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多