useReducer は useState の代替品ということで、この記事ではそれぞれの書き方と、useReducer と useContext を使って、ツリーの深い階層で使うための例を確認することができます。
useState
useState を使ったカウントアップ
import React, { useState } from "react";
function App() {
const [count, setCount] = useState(0);
return (
<div className="App">
{count}
<button onClick={() => setCount(count - 1)}>-</button>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
);
}
export default App;
【React Hooks】useStateの使用例コピペで確認
2023年01月12日
ReactuseReducer
useReducer を使った場合
import React, { useReducer } from "react";
function App() {
const [state, dispatch] = useReducer(reducer, { count: 0 });
return (
<div className="App">
{state.count}
<button onClick={() => dispatch({ type: 'decrement', value: 1 })}> - </button>
<button onClick={() => dispatch({ type: 'increment', value: 1 })}> + </button>
</div>
);
}
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + action.value }
case 'decrement':
return { count: state.count - action.value }
default:
throw new Error();
}
}
export default App;
1: useReducer をインポートします。
4: 初期化、第2引数として初期 state を渡します。
10~11: 呼び出し、引数に action を渡します。
15~24: action を元に state 値を返します。
useReducer
が useState
より好ましい使い方
複数の値にまたがる複雑な state ロジックがある場合や、前の state に基づいて次の state を決める必要がある場合です。また、
useReducer
を使えばコールバックの代わりにdispatch
を下位コンポーネントに渡せるようになるため、複数階層にまたがって更新を発生させるようなコンポーネントではパフォーマンスの最適化にもなります。
ドキュメントでは、コールバックを深い階層に受け渡すのを回避するために、useReducer で dispatch 関数を作って、それをコンテクスト経由で下の階層に渡す方法を推奨しています。
useReducer と useContext を使って、深い階層でも使えるように書き換えます。
【React Hooks】useContextの使用例コピペで確認
2023年01月18日
Reactsrc/
|-- index.js
|-- App.js
`-- context/
`-- counterContext.js
counterContexxt.js ファイルに処理を書いて createContext しています。
import { createContext, useReducer } from "react";
export const Counter = createContext();
export const CounterProvider = ({ children }) => {
const [state, dispatch] = useReducer(reducer, { count: 0 });
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + action.value }
case 'decrement':
return { count: state.count - action.value }
default:
throw new Error();
}
}
return (
<Counter.Provider value={{state, dispatch}}>
{children}
</Counter.Provider>
)
}
深い階層で使えるように値を渡します。
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import { CounterProvider } from './context/counterContext';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<CounterProvider>
<App />
</CounterProvider>
);
useContext で使います。
import React, { useContext } from "react";
import {Counter} from './context/counterContext';
function App() {
const counter = useContext(Counter)
return (
<div className="App">
{counter.state.count}
<button onClick={() => counter.dispatch({ type: 'decrement', value: 1 })}> - </button>
<button onClick={() => counter.dispatch({ type: 'increment', value: 1 })}> + </button>
</div>
);
}
export default App;
以上です。