In this tutorial we'll see an introduction of Redux Toolkit and how to use it with React application.
In the post
Redux in React With Examples we saw how you can create store using Redux and react-redux library. Though that is not the
suggested way to create redux store but I'll suggest to go through that post to get a better idea of how Redux
works. With the old way you generally have to write most of the logic yourself so it gives you a better understanding of
what is a store, reducer and action. But the suggested way now is to use configureStore()
provided by
@reduxjs/toolkit
library so let's try to understand how that works.
Using Redux toolkit
Though Redux library helps in managing global state and making state management more efficient but you may still experience the following problems.
- As the complexity of your project increases complexity of Redux also increases.
- Writing reducers and actions become more complex and their number also increases with bigger applications.
- State object may become big which results in keeping state immutable quite a complex task.
In order to address these issues and making it more convenient to work with Redux, the same team developed Redux toolkit. With Redux toolkit you can say that some of the steps that were done manually with Redux are now automatically derived. It also makes it more convenient to modify the stored state without worrying about its immutability as Redux toolkit uses immer library which takes care of state immutability behind the scene rather than you ensuring it.
The Redux Toolkit package is intended to be the standard way to write Redux logic.
Using @reduxjs/toolkit with react
Let's try to create the same counter application using Redux toolkit which was done in this post using Redux.
1. Install packages
If you already have a React application just navigate to the app base folder and run the following command to install Redux toolkit
npm install @reduxjs/toolkit react-redux
react-redux is the React binding library for Redux.
2. Create store
src\store\tkStore.js
import { configureStore } from "@reduxjs/toolkit"; const store = configureStore({ reducer: { } // that's where we'll add reducer }) export default store;
With Redux toolkit you start using configureStore() to create store rather than createStore() used with Redux.
configureStore() is an abstraction over the standard Redux createStore function that adds good defaults to the store setup for a better development experience.
configureStore accepts a single configuration object parameter, with many options. Options of interest to us initially are-
- reducer- To accept reucer functions.
- devTools- To indicate whether configureStore should automatically enable support for the Redux DevTools browser extension. Defaults to true.
For more details you can see the API- https://redux-toolkit.js.org/api/configureStore
3. Provide store to React
React Redux includes a <Provider /> component, which makes the Redux store available to the React app. We'll wrap <App /> component with the Provider which guarantees that the store provided with this Provider is available to App component and all its child components. That change can be done in index.js file.
import { Provider } from 'react-redux'; import store from './store/tkStore'; const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <React.StrictMode> <Provider store={store}><App /></Provider> </React.StrictMode> );
4. Create a state slice
You can import the createSlice
API from Redux Toolkit. This is the most important part as with slice you can write
reducer function and actions with in the slice.
src\slice\counterSlice.js
import { createSlice } from "@reduxjs/toolkit"; const counterSlice = createSlice({ name: 'counter', initialState: {value: 0}, reducers: { increment: (state) => { state.value++; }, decrement: (state) => { state.value--; }, increaseByValue: (state, action) => { state.value += action.payload; } } }); export const counterActions = counterSlice.actions; export default counterSlice.reducer;
Some important points to note here are-
- Creating a slice requires a name to identify the slice, which is given as ‘counter’ here.
name: 'counter',
- Slice also needs initial state value.
initialState: {value: 0},
- You can have one or more reducer functions to define how the state can be updated. You can think of reducer as
a map where key is the action name and the value is the logic to update state. For example, with this piece of code.
increment: (state) => { state.value++; },
Redux generates an action named 'increment'. With the use of createSlice Redux toolkit makes it easier to define reducers and actions, you also don't need condition statements (if or switch) to determine the correct action type. - Another very important thing is how state is changed. It looks like, now we are mutating state rather than creating a new state altogether.
state.value++;
This is permitted with Redux toolkit because it uses immer as explained already. - Export the reducers and actions so that they can be used where needed.
export const counterActions = counterSlice.actions; export default counterSlice.reducer;
You can also use object destructuring to export the generated action creators separately.export const { increment, decrement, increaseByValue} = counterSlice.actions;
5. Add reducer to the store
Now we have defined and exported the reducer so let's revisit the store to add reducer there.
import { configureStore } from "@reduxjs/toolkit"; import counterReducer from "../slice/counterSlice"; const store = configureStore({ reducer: { counterReducer: counterReducer } })
You can also add more than one slice reducers (an object of slice reducers)
configureStore({ reducer: { counterReducer: counterReducer, userReducer: userReducer } })
configureStore will automatically create the root reducer by passing this object to the Redux combineReducers utility.
6. Using actions in components
We'll use two hooks useSelector() and useDispatch() provided by react-redux. useSelector() hooks allows you to extract data from the Redux store state. useDispatch() hook is used to dispatch actions.
src\components\CounterWithRedux.js
import { useState } from "react"; import { useDispatch, useSelector } from "react-redux"; import { counterActions } from "../slice/counterSlice"; const CounterWithRedux = () => { const counter = useSelector((state) => state.counterReducer.value); const dispatch = useDispatch(); const [incrementByValue, setIncrementByValue] = useState(0); const incrementHandler = () => { dispatch(counterActions.increment()); } const decrementHandler = () => { dispatch(counterActions.decrement()); } const incrementByValueHandler = () => { dispatch(counterActions.increaseByValue(Number(incrementByValue))); } return ( <div> <h2>Counter</h2> <div> <button className="btn btn-primary mx-2" onClick={incrementHandler}>+</button> <span>{counter}</span> <button className="btn btn-primary mx-2" onClick={decrementHandler}>-</button> <div className="mt-2"> <input value={incrementByValue} onChange={e => setIncrementByValue(e.target.value)}></input> <button className="btn btn-primary mx-2" onClick={incrementByValueHandler}>Add Amount</button> </div> </div> </div> ); } export default CounterWithRedux;
Some important points to note here-
- We have used useSelector() to read data from store.
const counter = useSelector((state) => state.counterReducer.value);
What we are doing here is to go to the state produced by counterReducer.
Remember that we have given 'counterReducer' identifier to our reducer which is also named counterReducer.
import counterReducer from "../slice/counterSlice"; const store = configureStore({ reducer: { counterReducer: counterReducer } })
From that state we are extracting data from 'value' property. Again, that's how we defined the state.
initialState: {value: 0}
- We can import generated action creators which is imported in CounterSlice.js file.
import { counterActions } from "../slice/counterSlice";
Now we can dispatch the required action by accessing it through counterActions.
dispatch(counterActions.increment()); dispatch(counterActions.decrement());
- Note that Bootstrap is used here for styling.
Source: https://redux-toolkit.js.org/tutorials/quick-start
That's all for the topic Redux Toolkit in React With Examples. If something is missing or you have something to share about the topic please write a comment.
You may also like
- Redux Thunk in React With Examples
- createAsyncThunk in Redux + React Example
- React Example - Update Object in an Array of Objects
- props.children in React With Examples
- React useReducer Hook With Examples
- Generating PDF in Java Using iText Tutorial
- Java Stream concat() With Examples
- isinstance() in Python With Examples
- Spring Expression Language (SpEL) Tutorial
- Spring Data JPA @Query Annotation Example
No comments:
Post a Comment