Updating or Adding to an Existing Feature State
Intro
This tutorial will consists of adding state to an existing feature state.
Adding a New State
Here we are going to add a new reducer to clear the data on logout to the existing militaryServiceSlice.ts.
Current Slice Code
/src/store/slices/militaryServiceSlice.ts
import { PayloadAction, createSlice } from '@reduxjs/toolkit'
import * as api from 'store/api'
import { AppThunk } from 'store'
import { ScreenIDTypes, ServiceData } from '../api'
import { dispatchClearErrors, dispatchSetError, dispatchSetTryAgainFunction } from './errorSlice'
import { getCommonErrorFromAPIError } from 'utils/errors'
import { getDateFromString } from 'utils/formattingUtils'
import { isErrorObject } from 'utils/common'
import { max } from 'underscore'
export type MilitaryServiceState = {
serviceHistory: api.ServiceHistoryData
loading: boolean
error?: Error
mostRecentBranch?: string
needsDataLoad: boolean
preloadComplete: boolean
}
export const initialMilitaryServiceState: MilitaryServiceState = {
serviceHistory: [] as api.ServiceHistoryData,
loading: false,
needsDataLoad: true,
preloadComplete: false,
}
/**
* Redux action to get service history for user
*/
export const getServiceHistory =
(screenID?: ScreenIDTypes): AppThunk =>
async (dispatch) => {
dispatch(dispatchClearErrors(screenID))
dispatch(dispatchSetTryAgainFunction(() => dispatch(getServiceHistory(screenID))))
try {
dispatch(dispatchStartGetHistory())
const mshData = await api.get<api.MilitaryServiceHistoryData>('/v0/military-service-history')
dispatch(dispatchFinishGetHistory({ serviceHistory: mshData?.data.attributes.serviceHistory }))
} catch (error) {
if (isErrorObject(error)) {
dispatch(dispatchFinishGetHistory({ error }))
dispatch(dispatchSetError({ errorType: getCommonErrorFromAPIError(error), screenID }))
}
}
}
/**
* Redux slice that will create the actions and reducers
*/
const militaryServiceSlice = createSlice({
name: 'militaryService',
initialState: initialMilitaryServiceState,
reducers: {
dispatchStartGetHistory: (state) => {
state.loading = true
},
dispatchFinishGetHistory: (state, action: PayloadAction<{ serviceHistory?: api.ServiceHistoryData; error?: Error }>) => {
const { serviceHistory, error } = action.payload
const history = serviceHistory || state.serviceHistory
const latestHistory = max(history, (historyItem) => {
return getDateFromString(historyItem.endDate)
}) as ServiceData
return {
...state,
error,
mostRecentBranch: latestHistory?.branchOfService,
serviceHistory: history,
loading: false,
needsDataLoad: !!error,
preloadComplete: true,
}
},
},
})
export const { dispatchFinishGetHistory, dispatchStartGetHistory } = militaryServiceSlice.actions
export default militaryServiceSlice.reducer
Code after adding the logout reducer
Here we added the dispatchMilitaryHistoryLogout reducer function which we will extract an action to be dispatch on the logout Redux thunk.
/src/store/slices/militaryServiceSlice.ts
import { PayloadAction, createSlice } from '@reduxjs/toolkit'
import * as api from 'store/api'
import { AppThunk } from 'store'
import { ScreenIDTypes, ServiceData } from '../api'
import { dispatchClearErrors, dispatchSetError, dispatchSetTryAgainFunction } from './errorSlice'
import { getCommonErrorFromAPIError } from 'utils/errors'
import { getDateFromString } from 'utils/formattingUtils'
import { isErrorObject } from 'utils/common'
import { max } from 'underscore'
export type MilitaryServiceState = {
serviceHistory: api.ServiceHistoryData
loading: boolean
error?: Error
mostRecentBranch?: string
needsDataLoad: boolean
preloadComplete: boolean
}
export const initialMilitaryServiceState: MilitaryServiceState = {
serviceHistory: [] as api.ServiceHistoryData,
loading: false,
needsDataLoad: true,
preloadComplete: false,
}
/**
* Redux action to get service history for user
*/
export const getServiceHistory =
(screenID?: ScreenIDTypes): AppThunk =>
async (dispatch) => {
dispatch(dispatchClearErrors(screenID))
dispatch(dispatchSetTryAgainFunction(() => dispatch(getServiceHistory(screenID))))
try {
dispatch(dispatchStartGetHistory())
const mshData = await api.get<api.MilitaryServiceHistoryData>('/v0/military-service-history')
dispatch(dispatchFinishGetHistory({ serviceHistory: mshData?.data.attributes.serviceHistory }))
} catch (error) {
if (isErrorObject(error)) {
dispatch(dispatchFinishGetHistory({ error }))
dispatch(dispatchSetError({ errorType: getCommonErrorFromAPIError(error), screenID }))
}
}
}
/**
* Redux slice that will create the actions and reducers
*/
const militaryServiceSlice = createSlice({
name: 'militaryService',
initialState: initialMilitaryServiceState,
reducers: {
dispatchStartGetHistory: (state) => {
state.loading = true
},
dispatchFinishGetHistory: (state, action: PayloadAction<{ serviceHistory?: api.ServiceHistoryData; error?: Error }>) => {
const { serviceHistory, error } = action.payload
const history = serviceHistory || state.serviceHistory
const latestHistory = max(history, (historyItem) => {
return getDateFromString(historyItem.endDate)
}) as ServiceData
return {
...state,
error,
mostRecentBranch: latestHistory?.branchOfService,
serviceHistory: history,
loading: false,
needsDataLoad: !!error,
preloadComplete: true,
}
},
dispatchMilitaryHistoryLogout: () => {
return {
...initialMilitaryServiceState,
}
},
},
})
export const { dispatchFinishGetHistory, dispatchMilitaryHistoryLogout, dispatchStartGetHistory } = militaryServiceSlice.actions
export default militaryServiceSlice.reducer
That is all it takes to add a new state to an existing slice file. Now the dispatchMilitaryHistoryLogout could be imported to any file and be dispatched.