In this lesson, we'll build a simple application with two buttons that change the counter value. It will allow you to see the basic concepts of the Redux Toolkit.
Let us try to integrate it. We need two packages — react-redux and the toolkit itself:
# Run it at the root of the project
npm install @reduxjs/toolkit react-redux
Before we start putting the puzzle together, let's look at the directory structure that we'll start from. This structure is the simplest, but not the only possible one:
components/
| App.jsx
slices/
| index.js
| counterSlice.js
index.jsx
Let's start at the top level. Here we need the <Provider>
component, which contains the repository and sneaks it deep into the component tree via the context:
// file: index.jsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { Provider } from 'react-redux';
import App from './components/App.jsx';
import store from './slices/index.js';
const mountNode = document.getElementById('container');
const root = ReactDOM.createRoot(mountNode);
// We wrap the application in the `Provider` and pass the repository into it
root.render(
<Provider store={store}>
<App />
</Provider>,
);
We initialize the repository using the configureStore()
function. It knows how to combine reducers independently, unlike in Redux. As input, it takes an object with the reducer
key, the value of which is an object with reducers:
// file: slices/index.js
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from '../slices/counterSlice.js';
export default configureStore({
reducer: {
// The `counter` is the name inside the `state.counter` object
counter: counterReducer,
},
});
The reducers themselves are in the slices directory. Toolkit introduces a new concept — a slice which combines Reducers, Actions, and more. We'll talk more about it in the next lesson, but now we will see the code example:
// file: slices/counterSlice.js
import { createSlice } from '@reduxjs/toolkit';
// Initial value
const initialState = {
value: 0,
};
const counterSlice = createSlice({
name: 'counter',
initialState,
// Reducers in slices mutate the state and return nothing to the outside
reducers: {
increment: (state) => {
state.value += 1;
},
decrement: (state) => {
state.value -= 1;
},
// An example with some data
incrementByAmount: (state, action) => {
state.value += action.payload;
},
},
});
// The slice generates actions that export separately
// Actions are generated automatically from reducer key names
export const { increment, decrement, incrementByAmount } = counterSlice.actions;
// By default, the reducer generated by the slice is exported
export default counterSlice.reducer;
Now the most important thing, let's look at the Toolkit in action. Here we rely on hooks. As before, to change the state in the repository, we must pass an action to the dispatch()
function. We use the useDispatch()
function to get the dispatch:
// file: components/App.jsx
import React from 'react';
// The hooks are in `react-redux`
import { useSelector, useDispatch } from 'react-redux';
// Importing the desired actions
import { decrement, increment } from '../slices/counterSlice.js';
export default () => {
// Pulling data from the `store.state` (meaning the whole state)
const count = useSelector((state) => state.counter.value);
// The code returns the `store.dispatch()` method of the current store
const dispatch = useDispatch();
return (
<div>
<div>
<button
aria-label="Increment value"
onClick={() => dispatch(increment())}
>
Add
</button>
<span>{count}</span>
<button
aria-label="Decrement value"
onClick={() => dispatch(decrement())}
>
Take away
</button>
</div>
</div>
);
};
And here's a real-life example:
See the Pen js_redux_toolkit_integration-1 by Hexlet (@hexlet) on CodePen.
You do some of this initialization once and then seldom change it because you will add the majority of application code in components and slides. Unlike pure Redux, there will be much less of this code, thanks to slices and the ability to mutate data within reducers. More on this we are going to discuss in the next lesson.
Do it yourself
- Create a repository to experiment with the code from the lesson
- Repeat the steps from the lesson locally inside this repository
- Commit changes to the repository
Recommended materials
Are there any more questions? Ask them in the Discussion section.
The Hexlet support team or other students will answer you.
For full access to the course you need a professional subscription.
A professional subscription will give you full access to all Hexlet courses, projects and lifetime access to the theory of lessons learned. You can cancel your subscription at any time.