I'm experienced in Redux but I'm totally new to Redux Toolkit (RTK) and createSlice
. I'm trying to follow tutorials on official RTK Query docs but I'm getting lost.
I've created my actions: (assume there is a type called 'Model')
const setModel = createAction<Model>('setModel');
Then I've defined my state:
type MyState = {
model: Model;
}
const initialState: MyState = {
model: models[0], // points to a valid object of type Model
};
Then I try to create my slice:
export const mySlice = createSlice({
name: 'x',
initialState,
reducers: {
},
extraReducers: builder => {
builder.addCase(setModel, (state, action) => {
state.model = action.payload;
return state;
});
},
});
The docs seem to recommend the extraReducers
approach to use with action objects and builder directly, which also seems to implicitly support Immer. So I wrote my simple case for setModel
. However, when I try to use it in a component:
const dispatch = useDispatch();
dispatch(mySlice.actions.setModel(pickedItem));
mySlice.actions
is empty and doesn't include an entry named setModel
. It's not a TypeScript issue, putting a breakpoint when running also reveals that it's indeed empty:
Then I've read more and heard that extraReducers
doesn't create action creators, whereas reducers
does (which probably explains why my actions are empty). However, then I can't use the builder syntax which RTK Toolkit recommends in the first place.
At this point I'm totally lost.
How can I use createSlice
with strongly-typed and autogenerated action creators, or if that's not possible, what's the recommended pattern for createSlice
?
How can I use createSlice with strongly-typed and autogenerated action creators?
You can type the payloads of the reducers in the slice, the actions will be generated for you, and be correctly typed.
Example:
import { createSlice } from '@reduxjs/toolkit';
import type { PayloadAction } from '@reduxjs/toolkit';
type MyState = {
model: Model;
}
const initialState: MyState = {
model: models[0],
};
const mySlice = createSlice({
name: 'x',
initialState,
reducers: {
setModel: (state, PayloadAction<Model>) => {
state.model = action.payload;
},
},
});
export const {
setModel
} = mySlice.actions;
export default mySlice.reducer;
The extraReducers
are primarily used to handle external actions, e.g. asynchronous actions and actions generated by other slices.