Redux setup in a fast way
Renato Rocha
Posted on February 20, 2020
When we begining the development of our applications initialy each component become with their own state, do not needing share any informatiom across the application. However, as our application gets bigger, some information can become required for more than one component, as an example, a shopping cart informations.
At this time, we can lay hands of Redux for managing the state of our application. Well, due to the freedom that the Redux gives us, some difficults are pointed:
- "Configuring a Redux store is too complicated"
- "I have to add a lot of packages to get Redux to do anything useful"
- "Redux requires too much boilerplate code"
So was proposed the Redux Toolkit to helping us our Redux code.
Redux Toolkit
At the time that we need configuring the Redux for managing the state of our application, we can using the Redux core library, that leaves us free to decide anything about that setup. This can be good, due the flexibility but, some times we want to a fast way to get start. Redux Toolkit is a opinionated toolset that make easier to write good Redux applications and speeds up development.
Slices
In a typical redux configuration we creating our reducers that are passed in to a combineReducers function and the return of combineReducers are used by createStore function.
createStore(rootReducer)
^
|
const rootReducer = combineReducers({
todo: todoReducer,
other: () => ({}),
});
^
|
export default function todoReducer(
state = initialState,
action: TodoActionsTypes
): TodoState {
...
}
When we access the application state in our view component,
...
export default function Home(): ReactElement {
const data = useSelector((state: RootState) => state.todo.data);
...
}
and stay on top of the state we can see the object returned by combineReducers that representing the application state.
CombinedState<{
todo: TodoState;
other: {};
...
}>
So state.todo is a slice and todoReducer is a slice reducer that is used to update a slice (state.todo) of state.
Immutably
The Reducers that we creating are pure functions, that receiving a previous state and returns the next state. So one of their characteristics is the (immutability)[https://redux.js.org/basics/reducers/#handling-actions].
So when we creating our reducer, we can get something like:
export default function todoReducer(
state = initialState,
action: TodoActionsTypes
): TodoState {
switch (action.type) {
case CREATE_TODO_REQUEST:
return {
data: [...state.data, action.payload.todo]
};
...
default:
return state;
}
}
in that way we returns a new state and staying the immutability of state. however, some libraries, like immer, creating a temp state for us, so that, we can writing them in a more readable way. So the above code can be represented as:
export default function todoReducer(
state = initialState,
action: TodoActionsTypes
): TodoState {
return produce(state, draft => {
switch (action.type) {
case CREATE_TODO_REQUEST:
draft.data.push(action.payload.data);
break;
...
}
});
}
}
so draft.data.push(action.payload.data)
is more friendly than [...state.data, action.payload.todo]
.
A great news is that, Redux Toolkit uses immer internally, what allows us "mutate" the state, updating it in a more clearly way.
Example
Now we have a little background with some aspects of Redux Toolkit we can implement a counter example using TypeScript and Redux Toolkit.
When we uses the Redux core library, to configure our store we have the flux:
createStore(rootReducer);
^
|
const rootReducer = combineReducers({
todo: todoReducer,
other: () => ({}),
});
^
|
export default function todoReducer(
state = initialState,
action: TodoActionsTypes
): TodoState {
...
}
Using the Redux Toolkit we changing the createStore()
function by configureStore
function and the Redux Toolkit provide your owne combineReducers()
function.
When we creating our reducer, todoReducer, we use types that we define them in a separate file. As well as we define our actions creators in the same way, that is, in a separate file. However, will we use the createSlice()
function from Redux toolkit that will generates a slice reducer with corresponding action creators and action types.
counterSlice
To use the createSlice() function we need to pass the following parameters: a set of reducer functions, a slice name, and an initial state value.
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
export interface Integer {
value: number;
}
const initialState: Integer = {
value: 0
};
const counterSlice = createSlice({
name: "counter",
initialState,
reducers: {
increment(state, action: PayloadAction<Integer>) {
state.value = state.value + action.payload.value;
}
}
});
export const { increment } = counterSlice.actions;
export default counterSlice.reducer;
In the above code, createSlice()
create for us, an action creator named increment, action types and a reducer. If we execute console.log(increment)
, we see that the action type has the format: "counter/increment" that is the same that "slice name/reducer name".
Now with our slice reducer created the Redux config flux result in:
import { configureStore } from '@reduxjs/toolkit'
configureStore({reducer: rootReducer});
^
|
import { combineReducers } from '@reduxjs/toolkit'
const rootReducer = combineReducers({
counter: counterReducer,
});
^
|
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
const counterSlice = createSlice({
name: 'counter',
initialState,
reducers: {
increment(state, action: PayloadAction<Integer>) {
state.value = state.value + action.payload.value
}
}
})
export const {
increment
} = counterSlice.actions
export default counterSlice.reducer
So we could saw a little bit how the Redux tool kit can facility redux configuration, save us from creating actions types, actions creators manually and helping us to manipulating the state in a more fashion way. However Redux toolkit has more special charactistichs like, Redux-thunk native integration. Thus for more details and more examples, we can see in Redux Toolkit offcial docs that was very well written.
Posted on February 20, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.