I want to know if it's possible (or a good practice) to call dispatch(someDumbAction())
from an extraReducer.
For example, I have a setData()
action in reducers
object from createSlice
.
I want to call setData()
directly in my component. But I want to call it too in a extraReducer
listener, in order to reuse the reducer logic, like below:
// Thunk Action
export const getData = createAsyncThunk('data/getData', async (params) => {
return await api.get({ params })
})
// Slice creation
const slice = createSlice({
name: 'data',
initialState: [],
reducers: {
setData: (state, { payload }) => {
state.push(payload);
})
},
extraReducers: (builder: any) => {
builder.addCase(getData.pending, (state) => {
//...
})
builder.addCase(getData.rejected, (state) => {
//...
})
builder.addCase(getData.fulfilled, (state, { payload }) => {
// Here I want to dispatch `setData` action, in order to reuse that logic
// dispatch(setData(payload));
})
},
})
// In any component: dispatch(setData([...]);
export const getProducts = createAsyncThunk("getProducts", async () => { // I want dispatch action actionCallAPIPending like that // dispatch(actionLoading()); const response = await axios. get("api"); return response; }); reactjs.
Dispatching an action within a reducer is an anti-pattern. Your reducer should be without side effects, simply digesting the action payload and returning a new state object. Adding listeners and dispatching actions within the reducer can lead to chained actions and other side effects.
extraReducers allows createSlice to respond to other action types besides the types it has generated. As case reducers specified with extraReducers are meant to reference "external" actions, they will not have actions generated in slice. actions .
No. Reducers can never dispatch actions:
https://redux.js.org/style-guide/style-guide#reducers-must-not-have-side-effects
However, it looks like what you're really asking for here is the ability to run the same state update logic steps in multiple situations.
You could define the logic as a standalone reducer function, and reuse it in both cases:
function addItem(state, action) {
state.push(action.payload);
}
const slice = createSlice({
name: 'data',
initialState: [],
reducers: {
setData: addItem
},
extraReducers: (builder: any) => {
builder.addCase(getData.pending, (state) => {
//...
})
builder.addCase(getData.rejected, (state) => {
//...
})
builder.addCase(getData.fulfilled, addItem)
},
})
You could also define the function as part of reducers
, and then reference it inside of the extraReducers
handler:
const slice = createSlice({
name: 'data',
initialState: [],
reducers: {
setData: (state, { payload }) => {
state.push(payload);
})
},
extraReducers: (builder: any) => {
builder.addCase(getData.pending, (state) => {
//...
})
builder.addCase(getData.rejected, (state) => {
//...
})
builder.addCase(getData.fulfilled, (state, action) => {
slice.caseReducers.setData(state, action);
})
},
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With