useReducerでspread演算子を使用する必要がありますか?

Nov 20 2020

編集:ブライアンの答えを確認した後、2番目の例でも、削除...stateすると1番目の例と同じ動作が発生することがわかったため、この質問をするのは間違っていました。何が原因で間違った動作が見られたのかわかりません。ご不便をおかけして申し訳ありません。ブライアンの答えは、使用法の良い説明です。

次の2つのコードスニペットを比較してください。initialState一方が使用useStateし、もう一方が使用することを除いて、2つの状態を同時に更新することで同じことを行いますuseReducer

  1. useState

const {useState} = React;

const initialState = {
  name: 'John',
  age: 20
};

const Example = () => {
  const [state, setState] = useState(initialState);

  const handleName = () => {
    setState({...state, name: 'Tom'});
  }
  
  const handleAge = () => {
    setState({...state, age: 30});
  }

  return (
    <div>
      <p>{state.name}</p>
      <p>{state.age}</p>
      <button onClick={handleName}>
        Click to change name
      </button>
      <button onClick={handleAge}>
        Click to change age
       </button>
    </div>
  );
};

ReactDOM.render(
  <Example />,
  document.getElementById("react")
);
<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="react"></div>

  1. useReducer

const {useReducer} = React;

const initialState = {
    name: 'Tom',
    age: 30
}
const reducer = (state, action) => {
    switch (action.type) {
        case 'name':
            return {
                ...state,
                name: 'John'
            }
        case 'age':
            return {
                ...state,
                age: 25
            }
        default:
            return state
    }
}

const Example = () => {
  const [state, dispatch] = useReducer(reducer, initialState);
    return (
        <div>
            <p>Name: {state.name}</p>
            <p>Age: {state.age}</p>
            <button onClick={() => dispatch({ type: 'name' })}>Click to update name</button>
            <button onClick={() => dispatch({ type: 'age' })}>Click to update age</button>
        </div>
    )
};

ReactDOM.render(
  <Example />,
  document.getElementById("react")
);
<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="react"></div>

...state最初の例で削除すると、状態が単一のキーと値のペアに設定されるため、機能しなくなります。2番目の例でも同じことが起こると思っていましたが、そうではありませんでした。2番目の例は、スプレッド演算子を削除するとうまく機能します。

2番目の例について3つの質問があります。

  1. スプレッド演算子の用途は何ですか?
  2. スプレッド演算子を削除した後も機能するのはなぜですか?
  3. スプレッド演算子がなくてもうまく機能する場合、2番目の例ではスプレッド演算子は必要ないということですか?

回答

1 BrianThompson Nov 24 2020 at 17:17

私は、これは非常によく似質問であることを理解し、この1、私はうまくいけば、誤った情報を得ることから、将来のリーダーを防ぐために、とにかく答えを与えています。

どちらuseStateuseReducer全く以前の値のいずれかのマージを行います。以前の状態値を保持することは、状態の更新中(setState呼び出しまたはレデューサー関数定義のいずれか)の責任です。

これは、以下の変更されたコードではっきりとわかります。私が変更したのは...state、各スイッチケースからを削除することだけです。

const {useReducer} = React;

const initialState = {
    name: 'Tom',
    age: 30
}
const reducer = (state, action) => {
    switch (action.type) {
        case 'name':
            return {
                name: 'John'
            }
        case 'age':
            return {
                age: 25
            }
        default:
            return state
    }
}

const Example = () => {
  const [state, dispatch] = useReducer(reducer, initialState);
    return (
        <div>
            <p>Name: {state.name}</p>
            <p>Age: {state.age}</p>
            <button onClick={() => dispatch({ type: 'name' })}>Click to update name</button>
            <button onClick={() => dispatch({ type: 'age' })}>Click to update age</button>
        </div>
    )
};

ReactDOM.render(
  <Example />,
  document.getElementById("react")
);
<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="react"></div>

スプレッド演算子がこの目的で頻繁に使用される理由は、変更されていないすべての値を新しいオブジェクトに配置するための最も面倒な方法ではないためです。