Long time no Redux and i am getting rusty.
I remember back to the days that we had the reducer and all the app state management went through them.
Now it is really hard to understand the workflow.
So i have my store as this.
import { configureStore } from '@reduxjs/toolkit'
import userReducer from "../features/user";
export default configureStore({
reducer: {
user: userReducer
},
})
And this is the so called slice?
import {createSlice} from "@reduxjs/toolkit";
export const rootSlice = createSlice({
name: "user",
initialState: {
value: {
person_in: null,
code: null,
surname: null,
name: null,
active: null,
token: null,
org_unit: null,
available_days: null,
current_available_days: null,
total_days: null,
is_logged_in: false,
}
},
reducers: {
updateUser: (state, action) => {
state.value = action.payload
}
}
});
export const { updateUser } = rootSlice.actions;
export default rootSlice.reducer;
So i get that if i want to update the state of the user i go with
dispatch(updateUser({...});
How can i update just the code
attribute or any other attribute only?
CodePudding user response:
In order to achieve the ability to update a single property of your initial state object, you need to also implement the redux concept of Action
types.
You leverage the action.type
value within a switch/case
statement so that you can branch and update only what you need to: https://redux.js.org/tutorials/fundamentals/part-3-state-actions-reducers#handling-additional-actions.
I'm not too familiar with reduxjs/toolkit
but it looks like their createSlice
offers this in a slightly different but very intuitive manner: https://redux-toolkit.js.org/api/createSlice#the-extrareducers-builder-callback-notation. Wherein you add the extraReducers
function property to your createSlice
object.
Here is their sample code:
import { createSlice, createAction } from '@reduxjs/toolkit'
import { createStore, combineReducers } from 'redux'
const incrementBy = createAction('incrementBy')
const decrementBy = createAction('decrementBy')
const counter = createSlice({
name: 'counter',
initialState: 0,
reducers: {
increment: (state) => state 1,
decrement: (state) => state - 1,
multiply: {
reducer: (state, action) => state * action.payload,
prepare: (value) => ({ payload: value || 2 }), // fallback if the payload is a falsy value
},
},
// "builder callback API", recommended for TypeScript users
extraReducers: (builder) => {
builder.addCase(incrementBy, (state, action) => {
return state action.payload
})
builder.addCase(decrementBy, (state, action) => {
return state - action.payload
})
},
})
const user = createSlice({
name: 'user',
initialState: { name: '', age: 20 },
reducers: {
setUserName: (state, action) => {
state.name = action.payload // mutate the state all you want with immer
},
},
// "map object API"
extraReducers: {
[counter.actions.increment]: (
state,
action /* action will be inferred as "any", as the map notation does not contain type information */
) => {
state.age = 1
},
},
})
const reducer = combineReducers({
counter: counter.reducer,
user: user.reducer,
})
const store = createStore(reducer)
store.dispatch(counter.actions.increment())
// -> { counter: 1, user: {name : '', age: 21} }
store.dispatch(counter.actions.increment())
// -> { counter: 2, user: {name: '', age: 22} }
store.dispatch(counter.actions.multiply(3))
// -> { counter: 6, user: {name: '', age: 22} }
store.dispatch(counter.actions.multiply())
// -> { counter: 12, user: {name: '', age: 22} }
console.log(`${counter.actions.decrement}`)
// -> "counter/decrement"
store.dispatch(user.actions.setUserName('eric'))
// -> { counter: 12, user: { name: 'eric', age: 22} }
In their example they update the counter (single property) state, and they update the user (object property) state.