Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redux Toolkit: Dispatch an action from an extraReducers listener?

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([...]);
like image 755
sevenlops Avatar asked Dec 02 '20 10:12

sevenlops


People also ask

How do you dispatch action in createAsyncThunk?

export const getProducts = createAsyncThunk("getProducts", async () => { // I want dispatch action actionCallAPIPending like that // dispatch(actionLoading()); const response = await axios. get("api"); return response; }); reactjs.

Can we dispatch actions from reducers?

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.

What is extraReducers in Redux toolkit?

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 .


1 Answers

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);
    })
  },
})
like image 178
markerikson Avatar answered Oct 10 '22 00:10

markerikson