Arye Eidelman
Arye Eidelman

Reputation: 1966

redux-toolkit use an actionCreater in the same slice from another thunk reducer

I have a redux-thunk reducer generated with createSlice from redux-toolkit called getOne.

getOne fetches from an API and dispatches actions for the loading status, (startedLoading, finishedLoading, errorLoading).

I would like to also call another actionCreater created in the same slice called insert with the resulting data. or directly update the state from the getOne reducer.

import { createSlice } from "@reduxjs/toolkit"
import { startedLoading, finishedLoading, errorLoading } from '../slices/loadingSlice'
const apiEndpoint = "/api/v1"
const fetchOptions = { headers: { "Content-Type": "application/json" } }

const createModelSlice = function (modelName) {
  return createSlice({
    name: modelName,
    initialState: {byId: {}},
    reducers: {
      insert: (state, action) => {
        // ...
      },
      getOne: (state, action) => async (dispatch) => {
        // ...
        try {
          const response = await fetch(/*  */)

          // How would I update the store here?

          // 1. reference the insert actionCreater somehow.
          dispatch(insert({id: id, data: response))

          // 2. construct the action manually
          dispatch({action: `${modelName}/insert`, payload: {id: id, data: response))

          // 3. Mutate the state here and rely immer. (I'm not sure exactly how that works)
          state[modelName].byId[id] = response

          dispatch(finishedLoading({ key: /* */ }))
        } catch (error) {
          dispatch(errorLoading({ key: /* */ }))
        }
      },
      // ...
    }
  })
}

Upvotes: 2

Views: 2419

Answers (1)

Arye Eidelman
Arye Eidelman

Reputation: 1966

I missed the part of docs about slices not being able to use thunk. either way, it wouldn't work as the thunk actions don't map to a reducer but rather dispatch other actions multiple other reducers/actions.

I added thunk actions to the slice actions after creating the slice. this way I can reference the other actions


import { createSlice } from "@reduxjs/toolkit"
const slice = createSlice({
  name: name,
  initialState: { byId: {} },
  reducers: { /* */ }
}
slice.actions.myThunkAction = payload => async (dispatch, state) => {
  // ...
  slice.actions.nonThunkAction({ id: id, data: data})
  slice.actions.anotherNonThunkAction({ index payload.index, data: data.map( /* */ )})
}
import { createSlice } from "@reduxjs/toolkit"
import { startedLoading, finishedLoading, errorLoading } from '../slices/loadingSlice'
import encodeURLParams from '../tools/encodeURLParams'

const apiEndpoint = "/api/v1"
const fetchOptions = { headers: { "Content-Type": "application/json" } }

const createModelSlice = function (modelName) {
  const slice = createSlice({
    name: modelName,
    initialState: { byId: {} },
    reducers: {
      insert: (state, action) => {
        // ...
      },
      bulkInsert: (state, action) => {
        // ...
      },
    }
  })
  slice.actions.loadMany = payload => async (dispatch, state) => {
    dispatch(startedLoading({ key: /* */ }))
    try {
      const response = await fetch(/*  */)
      dispatch(slice.actions.insert(response))
      dispatch(finishedLoading({ key: /* */ }))
    } catch (error) {
      dispatch(errorLoading({ key: /* */ }))
    }
  }
  slice.actions.loadOne = payload => async (dispatch, state) => {
    dispatch(startedLoading({ key: /* */ }))
    try {
      const response = await fetch(/*  */)
      dispatch(slice.actions.bulkInsert(response))
      dispatch(finishedLoading({ key: /* */ }))
    } catch (error) {
      dispatch(errorLoading({ key: /* */ }))
    }
  }
  return slice
}

export default createModelSlice

Upvotes: 2

Related Questions