首页 > 解决方案 > 在什么情况下忽略 useReducer 中的扩展运算符会导致错误?

问题描述

在我看到的大多数useReducer示例中,扩展运算符已被用于保存状态。但是,在我所有的实践中,忽略它从未造成任何问题。似乎reducer 能够在没有扩展运算符的情况下保留状态本身。检查以下示例:

const initialState = {
    color: 'black',
    bgColor: 'white'
}

const reducer = (state, action) => {
    switch (action.type) {
        case 'dawn':
            return {
                ...state,
                color: 'white',
                bgColor: 'purple'
            }
        case 'reset':
            return initialState
        default:
            return {
                state
            }
    }
}

const UseReducerColorSetter = () => {
    const [state, dispatch] = useReducer(reducer, initialState);
    const { color, bgColor } = state;
    return (
        <>
            <div style={{ color: `${color}`, backgroundColor: `${bgColor}` }} className='card'>
                Hello
            </div>
            <button onClick={() => dispatch({ type: 'dawn' })}>Dawn mode</button>
            <button onClick={() => dispatch({ type: 'reset' })}>Reset</button>
        </>
    )
}

在这个例子中,移除...state不会导致任何问题,没有状态改变,没有控制台错误等。

在这个问题中,我问:是否有必要在 useReducer 中使用扩展运算符,忽略扩展运算符会导致问题useState,但仍然没有问题useReducer

有人可以为我提供一些忽略传播运算符导致问题的例子useReducer吗?减速器可以保持状态吗?

标签: javascriptreactjs

解决方案


这是一个运行示例,显示如果您不替换减速器中的所有对象属性,它们将丢失。将控制台记录的初始值与打印的结果进行比较。

const initialState = {
  color: "black",
  bgColor: "white"
};

const reducer = (state, action) => {
  switch (action.type) {
    case "dawn":
      return {
        bgColor: "purple" // Updated to only return one property to illustrate the problem
      };
    case "reset":
      return initialState;
    default:
      return {
        state
      };
  }
};

function App() {
  const [state, dispatch] = React.useReducer(reducer, initialState);

  React.useEffect(() => {
    console.log("Initial: ", state)
    dispatch({ type: "dawn" });
  }, []);

  return <div>{JSON.stringify(state)}</div>;
}

ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>

注意reducer 函数的签名 (state, action) => newState。此函数返回新状态。所以无论你return从减速器中得到什么,它都是新的状态值。这意味着在不传播根状态对象的情况下,您将丢失任何未在新对象中明确设置的值。

要直接回答您的问题,当您的状态是数组或对象时,不将先前的状态传播到 reducer 更新会导致错误,并且您不会手动替换该结构中的每个值。

如果您总是设置每个对象属性或返回之前的状态,您将永远不会遇到错误。这是您在问题中给出的场景,这就是为什么它似乎没有必要。


推荐阅读