Appearance
Redux Toolkit
Redux Toolkit is a library created by the official Redux Team to provide an opinionated but simple toolkit that handles the majority of Redux pattern. It's an abstraction on top of redux to standardize pattern and reduce boilerplate.
APIs
Redux Toolkit includes a list of APIs or helper functions that take cares of common Redux patterns. These include:
configureStore()
Simplifies the process of setting up the Redux Store by:
- Combine slice reducers into the root reducer function
- Adds thunk middleware.
- Automatically set up Redux DevTools Extension
- Calls
createStore
Before:
js
import { createStore, applyMiddleware, combineReducers } from 'redux';
import thunk from 'redux-thunk';
import { composeWithDevTools } from 'redux-devtools-extension';
import userReducer from './reducers/userReducer';
import postsReducer from './reducers/postsReducer';
// Combine reducers manually
const rootReducer = combineReducers({
user: userReducer,
posts: postsReducer,
});
// Configure store with middleware and DevTools
const store = createStore(
rootReducer,
composeWithDevTools(applyMiddleware(thunk))
);After:
js
import { configureStore } from '@reduxjs/toolkit';
import userReducer from './reducers/userReducer';
import postsReducer from './reducers/postsReducer';
// Configure store with slices, auto-applied middleware, and DevTools
const store = configureStore({
reducer: {
user: userReducer,
posts: postsReducer,
},
});
export default store;createReducer() and createAction()
Simplifies creating reducers by utilizing Immer under the hood to allow "mutation" on the state directly i.e. doesn't require the reducer to return the full state object for reach update.
Before: Creating a reducer and creating action functions:
js
const initialState = { value: 0 }
const INCREMENT = 'increment'
function increment(amount) {
return {
type: INCREMENT,
payload: amount,
}
}
function counterReducer(state = initialState, action) {
switch (action.type) {
case 'increment':
return { ...state, value: state.value + 1 }
case 'decrement':
return { ...state, value: state.value - 1 }
case 'incrementByAmount':
return { ...state, value: state.value + action.payload }
default:
return state
}
}After: Actions and Reducers require less boilerplates:
js
import { createAction, createReducer } from '@reduxjs/toolkit'
const increment = createAction('counter/increment')
const decrement = createAction('counter/decrement')
const incrementByAmount = createAction('counter/incrementByAmount')
const initialState = { value: 0 }
const counterReducer = createReducer(initialState, (builder) => {
builder
.addCase(increment, (state, action) => {
state.value++
})
.addCase(decrement, (state, action) => {
state.value--
})
.addCase(incrementByAmount, (state, action) => {
state.value += action.payload
})
})createSlice()
The above can be further simplified with createSlice() which internally uses createAction() and createReducer() to automatically creates action creators, action types, reducers and state all in one function.
In Redux, we traditionally created the following items separately:
- initialState
- action types
- actions creators
- reducers
All of these are combined into a single createSlice() function.
createSlice() takes the following as arguments:
- name: the slice name used for scoping the actions
- initialState: the initial state of the slice
- reducers: an object for the list of reducer (the keys become the actions)
js
import { createSlice } from '@reduxjs/toolkit'
const initialState = { value: 0 }
const counterSlice = createSlice({
name: 'counter',
initialState,
reducers: {
increment(state) {
state.value++
},
decrement(state) {
state.value--
},
incrementByAmount(state, action) {
state.value += action.payload
},
},
})
export const { increment, decrement, incrementByAmount } = counterSlice.actions
export default counterSlice.reducercreateSlice also has these following arguments
extraReducers: for adding more reducers that doesn't automatically create actions.reducerPath: a string to customize the reducers location path. Defaults toname.selectors: an object of selectors. Create selectors functions with the sliceState in the arguments.
Conclusion
Redux Toolkit provides several APIs to simplify Redux. For the majority of use cases createSlice() is more than enough to provide all the Redux functionalities while reducing a lot of boilerplate.