【React】Redux Toolkitを使ってみた
仕事ではReact Reduxを使用しているのですが、今更ながらRedux Toolkitを試してみた際のメモです。
環境構築
npx create-react-app redux-toolkit-example --template redux
標準でCounterのサンプルがあるので、これを見ていきます。
createSlice
nameがsliceの識別名、initialStateが初期値です。
他は後述します。
import { createSlice } from '@reduxjs/toolkit';
const initialState = {
value: 0,
status: 'idle',
};
export const counterSlice = createSlice({
name: 'counter',
initialState,
reducers: {
increment: (state) => {
state.value += 1;
},
decrement: (state) => {
state.value -= 1;
},
incrementByAmount: (state, action) => {
state.value += action.payload;
},
},
extraReducers: (builder) => {
builder
.addCase(incrementAsync.pending, (state) => {
state.status = 'loading';
})
.addCase(incrementAsync.fulfilled, (state, action) => {
state.status = 'idle';
state.value += action.payload;
});
},
});
export const { increment, decrement, incrementByAmount } = counterSlice.actions;
export const selectCount = (state) => state.counter.value;
export const incrementIfOdd = (amount) => (dispatch, getState) => {
const currentValue = selectCount(getState());
if (currentValue % 2 === 1) {
dispatch(incrementByAmount(amount));
}
};
export default counterSlice.reducer;
reducers
ここにactionを記入します。
サンプルでは、
1. increment
2. decrement
3. incrementByAmount
の3つのアクションが定義されています。
reducers: {
increment: (state) => {
state.value += 1;
},
decrement: (state) => {
state.value -= 1;
},
incrementByAmount: (state, action) => {
state.value += action.payload;
},
},
createAsyncThunk
React ReduxではRedux ThunkでReduxで非同期関数を扱っていましたが、Redux Toolkitでは createAsyncThunkを使用します。
createAsyncThunkの第1引数にアクション名、第2引数に非同期関数を渡します。
import { createAsyncThunk } from '@reduxjs/toolkit';
export const incrementAsync = createAsyncThunk(
'counter/fetchCount',
async (amount) => {
const response = await fetchCount(amount);
return response.data;
}
);
extraReducers
非同期処理の後処理になります。
pendingが処理中、fulfilledが正常終了時の後処理になります。
サンプルにはありませんが、rejectedが失敗時になります。
extraReducers: (builder) => {
builder
.addCase(incrementAsync.pending, (state) => {
state.status = 'loading';
})
.addCase(incrementAsync.fulfilled, (state, action) => {
state.status = 'idle';
state.value += action.payload;
});
},
Store
Storeに先程作成したReducerを登録しています。
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from '../features/counter/counterSlice';
export const store = configureStore({
reducer: {
counter: counterReducer,
},
});
useSelector
コンポーネント側でstoreのstateを取得します。
import { useSelector } from 'react-redux';
import {
selectCount,
} from './counterSlice';
export function Counter() {
const count = useSelector(selectCount);
}
useDispatch
dispatchの引数にaction(下記の例ではincrement)を渡す事で、イベント発火時にreducerのactionが実行されます。
import { useDispatch } from 'react-redux';
export function Counter() {
const dispatch = useDispatch();
return (
<div>
<button
className={styles.button}
aria-label="Increment value"
onClick={() => dispatch(increment())}
>
</div>
);
}
今回はサンプルを試してみただけですが、React Reduxより取っ付きやすくなっているなと感じました。
ディスカッション
コメント一覧
まだ、コメントがありません