Reactで状態管理をする方法についてまとめてみる
Reactの実務経験は無いので、誤りがあれば指摘いただければ幸いです!
状態管理の手法
- useState
- useReducer
useState
関数コンポーネントの中でローカルなstateを使うことができるフック
useState
は現在の state の値と、更新関数のペアを返します
Todos
Component
const Todos = () => {
const [title, setTitle] = useState("")
const handleSubmit = (e) => {
e.preventDefault();
const data = {
id: new Date().getTime(),
title,
created_at: new Date()
};
setTodos((prevData) => [...prevData, data]);
setTitle("");
};
return (
<>
<h2>Todos</h2>
<form onSubmit={handleSubmit}>
<input
type="text"
onChange={(e) => setTitle(e.target.value)}
value={title}
/>
</form>
<ul>
{todos.map((todo) => (
<TodoItem todo={todo} key={todo.id} />
))}
</ul>
</>
);
};
export default Todos;
コンポーネント単位で管理しているため、親子関係になっていればpropsとしてstateを渡し、他のコンポーネントでデータを反映させることは可能。
親子関係がなく、それぞれが独立したコンポーネントの場合、後述する Redux
useContext
等の props
以外の情報共有手段が必要になる。
公式
https://ja.reactjs.org/docs/hooks-state.html
codesandbox
https://codesandbox.io/s/usestate-todo-app-2i51b?file=/src/components/TodoItem.jsx:105-113
useReducer
useState
では、 現在のstate
とstateを更新するための関数が返ってきていました。
useReducer
は、第一引数に関数(reducer)、第二引数にstate
の初期値を渡すと、現在のstate
とdispatch
メソッドとペアで返ってきます。
dispatch
は、reducer
に action
を dispatch
し、reducer
に伝えます。
action
を受け取ったreducer
は、action.type
で分岐して処理する内容をきめている。
ざっくり書くと、
一つ前の state
と dispatch
された action
を使って新しいstateを生成するための 「関数」 です。
公式サイトより↓
// state初期値
const initialState = {count: 0};
// action.type によって処理する内容を決める
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] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
<button onClick={() => dispatch({type: 'increment'})}>+</button>
</>
);
}
onClick={() => dispatch({type: 'decrement'})}
のように、 action
を dispatch
すると
reducer
関数の中で、 action.type
の分岐が実行される。
case 'decrement':
return {count: state.count - 1};
codesandboxで、簡単なフォームを作ってみました。
このサンプルでは、 use-immer
を使用しています。
codesandbox
https://codesandbox.io/s/usereducer-form-mjnzj?file=/src/App.js
Flux In-Depth Overview
https://facebook.github.io/flux/docs/in-depth-overview#structure-and-data-flow
公式 useReducer
https://ja.reactjs.org/docs/hooks-reference.html#usereducer