Redux のセッティングは難しいイメージですが、Redux Tookit を使うと、簡単にグローバルな状態を管理することができます。
手順は、ほとんど公式サイト(https://redux-toolkit.js.org/)を参考にしました。
まずは、React Redux と Redux Toolkit をインストールします。
プロジェクトのターミナルを開き、npm install @reduxjs/toolkit react-reduxを実行します。
src フォルダ内に app フォルダを作成します。
app フォルダ内に store.ts を作成しましょう。
Redux の store を作成します。
Redux Toolkit のconfigureStoreが、store のセットアップを簡素化してくれます。
configureStoreの中には、状態を更新するためのreducerを設定します。
tsx
import { configureStore } from "@reduxjs/toolkit";
export const store = configureStore({
reducer: {},
});
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
次に index.tsx に React Redux のProviderを設定します。
先程作成したstoreもインポートします。
tsx
import { store } from "./app/store";
import { Provider } from "react-redux";
const root = ReactDOM.createRoot(
document.getElementById("root") as HTMLElement
);
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
src フォルダ内に、features フォルダを作成します。
features フォルダ内にさらに counter フォルダを作成し、counterSlice.ts を作成します。
counterSlice.ts に初期状態とスライスを識別するための名前、状態を更新する方法を設定します。
今回は、初期状態をvalue: 23、スライスの名前をcounterとします。
状態の更新は、カウンターのように、incrementを実行すると 1 プラス、decrementを実行すると 1 マイナスとします。
tsx
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
export interface CounterState {
value: number;
}
const initialState: CounterState = {
value: 23,
};
export const counterSlice = createSlice({
name: "counter",
initialState,
reducers: {
increment: (state: { value: number }) => {
state.value += 1;
},
decrement: (state: { value: number }) => {
state.value -= 1;
},
},
});
export const { increment, decrement } = counterSlice.actions;
export default counterSlice.reducer;
初めに作成した、store.ts に移動します。
reducer 内にスライスの名前とスライスの名前に Reducer を付けて指定します。
tsx
export const store = configureStore({
reducer: {
counter: counterReducer,
},
});
App.tsx へ移動します。
React Redux のuseSelectorとuseDispatchをインポートします。
また、store.ts からRootStateをインポートします。
さらに、counterSlice.ts からdecrement、incrementをインポートします。
tsx
import { RootState } from "./app/store";
import { useSelector, useDispatch } from "react-redux";
import { decrement, increment } from "./features/counter/counterSlice";
ストアからデータを読み込むために、useSelectorを設定します。
Redux のactionをdispatchするために、useDispatchも設定しましょう。
tsx
const age = useSelector((state: RootState) => state.counter.value);
const dispatch = useDispatch();
カウンターボタンを return 内に作成します。
tsx
function App() {
const age = useSelector((state: RootState) => state.counter.value);
const dispatch = useDispatch();
return (
<>
<div>
<button
aria-label="Increment value"
onClick={() => dispatch(increment())}
>
+
</button>
{age}
<button
aria-label="Decrement value"
onClick={() => dispatch(decrement())}
>
-
</button>
</div>
</>
);
}
一通り完成したので、ブラウザで確認すると、
初期値である 23 が表示されています。
+ボタンをクリックすると、
数が 1 追加されました。
試しに、別のコンポーネントでも状態が管理できるか、確認してみましょう。
components フォルダ、Age.tsx
tsx
import React from "react";
import { RootState } from "../app/store";
import { useSelector } from "react-redux";
const Age = () => {
const age = useSelector((state: RootState) => state.counter.value);
return <>{age}歳</>;
};
export default Age;
App.tsx
tsx
<>
<Age />
<div>
<button aria-label="Increment value" onClick={() => dispatch(increment())}>
+
</button>
{age}
<button aria-label="Decrement value" onClick={() => dispatch(decrement())}>
-
</button>
</div>
</>
ブラウザで確認すると、
Redux で管理している状態が、別コンポーネントでも使用することができました。