useReducerでspread演算子を無視すると、どのような場合にバグが発生しますか?

Nov 25 2020

useReducer私が見たほとんどの例では、スプレッド演算子は状態を保持するために使用されています。しかし、私のすべての実践において、それを無視しても問題は発生しませんでした。レデューサーは、spread演算子なしで状態自体を保持できるようです。次の例を確認してください。

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でspread演算子を使用する必要があります。spread演算子を無視するとuseState、で問題が発生しましたが、それでも問題はありませんuseReducer

誰かが私に問題を引き起こしているスプレッド演算子を無視するいくつかの例を提供できますかuseReducer?レデューサーは状態を保持できますか?

回答

1 BrianThompson Nov 24 2020 at 23:53

これは、レデューサーですべてのオブジェクトプロパティを置き換えないと、それらが失われることを示す実行例です。コンソールに記録された初期値を印刷結果と比較します。

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>

レデューサー関数のシグネチャに 注意してください(state, action) => newState。この関数は新しい状態を返します。したがってreturn、レデューサーからのあなたは、全体として新しい状態値です。これは、ルート状態オブジェクトを拡散しないと、新しいオブジェクトに明示的に設定されていない値が失われることを意味します。

質問に直接答えるために、レデューサーの更新で以前の状態を拡散しないと、状態が配列またはオブジェクトである場合にバグが発生し、その構造内のすべての値を手動で置き換えるわけではありません。

あなたがいる場合、必ず各オブジェクトのプロパティを設定したり、以前の状態に戻るには、バグに遭遇することはありません。これはあなたが質問で与えたシナリオであり、それが不必要に思われる理由です。

SergioVargas Nov 24 2020 at 23:28

特定のケースでは、状態値(colorとbgColor)を変更しているため、影響を受けたり問題が発生したりすることはありません。たとえば、色のみを変更する場合、spread演算子を無視すると、状態はbgColor値なしのままになります。アプリが常にbgColorを持つことを期待している場合、問題が発生する可能性があります。

 case 'blue':
            return {
                color: 'blue',
            }