ReduxToolsのreducersとextraReducersってどう違うんだ?
ReduxToolkitの基本的なことは公式を見てください。
extraReducersはスライスをまたいでアクションを受け取ることが出来る。
試したこと。
5つのソース
犬猿の仲ではないですが、猿と犬のスライスを作って実験しました。
スライスは./slices/monkeySlice.ts
と./slices/dogSlice.ts
を用意
んでストアのstore.ts
と表示用のTestControl.tsx
を用意
hooks.ts
はお決まりのやつ。
合計5つのファイルを用意。
hooks.ts
お決まりのやつ
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
import { AppDispatch, RootState } from "./store";
export const useAppDispatch: () => AppDispatch = useDispatch;
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
slices/monkeySlice.ts
import { createAction, createSlice } from "@reduxjs/toolkit";
export const ukkiAction = createAction('ukki');
// 追加
export const monkeyUkkiAction = createAction('monkey/ukki');
const initialState = { x: 123 }
const monkeySlice = createSlice({
name: 'monkey',
initialState,
reducers: {
// monkey/ukki
ukki: (s, x) => {
console.log(`monkey.reducer:ukki = ${x.payload} / ${x.type}`)
},
// monkey/wan
wan: (s, x) => {
console.log(`monkey.reducer:wan = ${x.payload} / ${x.type}`)
}
},
extraReducers: (builder) => {
// ukki
builder.addCase(
ukkiAction,
(s, x) => {
console.log(`monkey.extra:ukki = ${x.payload} / ${x.type}`);
}
)
// monkey/wan
builder.addCase(
monkeySlice.actions.wan,
(s, x) =>
{
console.log(`monkey.extra:wan = ${x.payload} / ${x.type}`);
}
)
// monkey/ukki
builder.addCase(
monkeyUkkiAction,
(s, x) => {
console.log(`monkey.extra:monkey/ukki = ${x.payload} / ${x.type}`);
}
)
}
})
export default monkeySlice;
console.log(ukkiAction.type); // ukki
console.log(monkeyUkkiAction.type); // monkey/ukki
console.log(monkeySlice.actions.ukki.type); // monkey/ukki
console.log(monkeySlice.actions.wan.type); // monkey/wan
slices/dog.ts
import { createSlice } from "@reduxjs/toolkit";
import monkeySlice, { ukkiAction } from "./monkeySlice";
const initialState = { x: 456 }
const exampleSlice = createSlice({
name: 'dog',
initialState,
reducers: {
// dog/ukki
ukki: (s, x) => {
console.log(`dog.reducer:ukki = ${x.payload} / ${x.type}`);
},
// dog/wan
wan: (s, x) =>
{
console.log(`dog.reducer:wan = ${x.payload} / ${x.type}`);
}
},
extraReducers: (builder) => {
// ukki
builder.addCase(
ukkiAction,
(s, x) => {
console.log(`dog.extra:ukki = ${x.payload} / ${x.type}`);
}
)
// monkey/wan
builder.addCase(
monkeySlice.actions.wan,
(s, x) => {
console.log(`dog.extra:wan = ${x.payload} / ${x.type}`);
}
)
// monkey/ukki
builder.addCase(
monkeySlice.actions.ukki,
(s, x) => {
console.log(`dog.extra:monkey/ukki = ${x.payload} / ${x.type}`);
}
)
}
})
export default exampleSlice;
store.ts
import { configureStore } from "@reduxjs/toolkit";
import monkeySlice from "./slices/monkeySlice";
import dogSlice from "./slices/dogSlice";
export const store = configureStore({
reducer: {
monkey: monkeySlice.reducer,
dog: dogSlice.reducer
}
})
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
TestControl.ts
import React from "react"
import { useAppDispatch } from "../redux/hooks"
import monkeySlice, { monkeyUkkiAction, ukkiAction } from "../redux/slices/monkeySlice";
export const TestControl = () => {
const dispatch = useAppDispatch();
return (
<>
<input type="button"
value="ukki"
onClick={e => dispatch(ukkiAction())} />
<input type="button"
value="wan"
onClick={e => dispatch(monkeySlice.actions.wan(null))} />
<input type="button"
value="monkey/ukki"
onClick={e => dispatch(monkeyUkkiAction())} />
</>
)
}
前提知識
その前に前提知識。
monkeySlice.tsのこの4行。
console.log(ukkiAction.type); // ukki
console.log(monkeyUkkiAction.type); // monkey/ukki
console.log(monkeySlice.actions.ukki.type); // monkey/ukki
console.log(monkeySlice.actions.wan.type); // monkey/wan
3行目、createSlice()
のreducersに追加した場合、スライスのactions
から取得出来ます。
アクションタイプの命名規則はname
プロパティがプレフィックスになります。
name
がmonkey
で関数がukki
の場合、アクションタイプはmonkey/ukki
です。
reducersにアクションタイプがあるとそちらの関数が実行され、
extraReducersの方は実行されないっぽい。
実行結果
では実行結果。
TestControl.tsx
にて。
[ukki]ボタン
dispatch(ukkiAction())
ukkiAction()のアクションタイプはukki
なので呼び出されるのはmonkeyとdogのextractReducersで受け取れる。
monkey.extra:ukki = undefined / ukki
dog.extra:ukki = undefined / ukki
[wan]ボタン
dispatch(monkeySlice.actions.wan(null))
reducersで追加したwan
は命名規則によりmonkey/wan
になる。
monkey.reducer:wan = null / monkey/wan
dog.extra:wan = null / monkey/wan
monkeySliceではreducersにmonkey/wan
があるので、extractReducers側のmonkey.extra:wan
は呼び出されていない。
[monkey/ukki]ボタン
dispatch(monkeyUkkiAction())
アクションタイプはmonkey/ukki
になるので。
monkey.reducer:ukki = undefined / monkey/ukki
dog.extra:monkey/ukki = undefined / monkey/ukki
こちらもreducers側にmonkey/ukki
があるのでmonkey.extra:monkey/ukki
は呼ばれてないことがわかる。