Reduxは、Reactなどのフロントエンド開発において、アプリケーション全体の状態を管理および更新するためのライブラリです。Reduxを用いることで、デバッグや状態の追跡が容易になります。
Reduxとは
Reduxとは、Reactなどで開発されたすべてのコンポーネントからアクセス可能なグローバルな状態管理を行うライブラリです。なぜ、Reduxを利用する必要があるのでしょうか?Reactでは、親子関係にあるコンポーネントでしかデータの受け渡しができません。そのため、孫コンポーネントにデータを受け渡すためにはデータをバケツリレーする必要があり、開発の規模が大きくなるほどデータの受け渡しは煩雑になります。一方、Reduxを利用すると、データを一元管理することができ、どこからでもアクセスできるため、データ管理が簡素化され、デバッグも容易になります。
Reduxの主な要素
Action
Actionとは、アプリケーションで発生したイベントを表すプレーンなJavaScriptオブジェクトです。Actionは、通常Actionの種類を表すtypeプロパティと発生した状態変更を格納するpayloadプロパティを持ちます。
Reducer
Reducerとは、現在の状態とActionを受け取り、受け取ったActionの種類に基づいて、新しい状態を返す関数です。 Reducerは副作用を持たず、純粋関数(同じ入力に対して常に同じ出力を返す)であるため、アプリケーションの動作を予測しやすくします。
Store
Storeとは、現在のReduxアプリケーションの状態を保存するオブジェクトです。アプリケーションのすべての状態を単一のオブジェクトとして管理し、状態の変更を一元化します。また、状態の取得、更新、サブスクリプションなどの機能を提供し、アプリケーション全体のデータフローを制御します。
Reduxの基本原則
Reduxには3つの基本原則があります。これらの原則を守って利用することで、Reduxの利点を最大限引き出すことができます。
Single source of truth(信頼できる唯一の情報源)
1つめの原則は、アプリケーションのすべての状態を単一のストアで管理することです。この原則を守ることにより、データの一貫性が保たれ、状態の追跡が容易になります。
State id Read-Only(状態は読み取り専用)
2つめの原則は、状態を直接変更せず、アクションを通じてのみ変更を行うことです。この原則を守ることにより、どこで状態の変更が起こっているのか、どのような変更が行われているのか追跡しやすくなります。
Changes are Made with Pure Function(変更は純粋関数で行う)
3つめの原則は、状態の変更を純粋関数で行うことです。この原則を守ることにより、状態の変更が予測しやすくなります。
Todoアプリの作成
ここからは、Reduxを利用したTodoアプリの作成例を見ていきます。 まずは、Redux ToolkitとReact-Reduxパッケージをプロジェクトに追加します。
npm install @reduxjs/toolkit react-redux
次に、Todoアプリに必要なアクションとリデューサーを作成します。ここでは、Redux Toolkitを使用しています。Redux Toolkitでは、Reducer、ActionをまとめたSliceという単位で管理することで、コードをより簡潔にすることができます。
// TodoSlice.js
import { createSlice } from "@reduxjs/toolkit";
export const todoSlice = createSlice({
name: 'todo',
initialState: {
list: [],
nextId: 1
},
reducers: {
add: (state, action) => {
state.list.push({
id: state.nextId,
...action.payload,
});
state.nextId += 1;
},
done: (state, action) => {
const index = state.list.findIndex(todo => todo.id === Number(action.payload.id));
if (index !== -1) {
state.list[index].isDone = true;
}
},
remove: (state, action) => {
state.list = state.list.filter(todo => todo.id !== Number(action.payload.id));
},
},
});
export const { add, done, remove } = todoSlice.actions;
export default todoSlice.reducer;
次に、ストアを作成し、スライスを追加します。
// store.js
import { configureStore } from '@reduxjs/toolkit';
import todoReducer from '../slice/TodoSlice';
export default configureStore({
reducer: {
todo: todoReducer
}
});
最後に、Todoリストを作成します。useSelector関数で状態を取得し、dispatch関数の中にリデューサーを設定することで、状態を更新できます。
// ReduxTodo.js
import { useDispatch, useSelector } from 'react-redux';
import { add, done, remove } from '../slice/TodoSlice';
import { useState } from 'react';
export default function ReduxTodo() {
const [title, setTitle] = useState('');
const todo = useSelector(state => state.todo.list);
const dispatch = useDispatch();
const handleChangeTitle = e => setTitle(e.target.title);
const handleAdd = () => {
dispatch(add({ title: title, isDone: false }));
};
const handleDone = () => {
dispatch(done({ id: e.target.dataset.id }));
};
const handleRemove = () => {
dispatch(remove({ id: e.target.dataset.id }));
};
return (
<div>
<label>
やること:
<input type="text" name="todo"
value={title} onChange={handleChangeTitle} />
</label>
<button type="button"
onClick={handleAdd}>追加</button>
<hr />
<ul>
{todo.map(item => (
<li key={item.id}
className={item.idDone ? "done" : ""}>
{item.title}
<button type="button"
onClick={handleDone} data-id={item.id}>済
</button>
<button type="button"
onClick={handleRemove} data-id={item.id}>削除
</button>
</li>
))}
</ul>
</div>
);
}
まとめ
Reduxは、大規模アプリケーションの状態管理において重要な役割を果たします。一方、すべてのアプリにReduxが必要なわけではありません。開発するアプリの種類についてじっくり考え、取り組んでいる課題を解決するのに最適なツールを選ぶことが大切だと思います。

