Intro
This quick guide will cover the basics of using React-Redux.
They’ll be using a regular create-react-app
template, but I’ll be building using Vite.
npm create vite@latest # answer the questions
# OR
npm create vite@latest <name> -- --template react
Then install the packages for Redux:
npm install @reduxjs/toolkit react-redux
Creating the Store
We need to initialize the store and export it, while auto configuring the DevTools. // browser plugin
import { configureStore } from '@reduxjs/toolkit'
export default configureStore({
reducer: {},
})
Providing the Store to React - Provider
The Provider
component is a wrapper around our app similar to how Context
is.
Steps:
- Go to your
App
component - Import
store
we created and importProvider
fromreact-redux
- Wrap your App in Provider and pass
store
to it as a prop.
Alternatively, can wrap it where you use App
component…
Example:
<Provider store={store}>
<App />
</Provider>
Creating a Redux State Slice
Create a folder in src
for features, and then a folder for the corresponding feature and its slice, for example src/features/cooker/cookerSlice.js
.
Slices require:
- A string name
- An initial state value
- 1+ reducer functions to determine how state can be updated
Steps
- import
createSlice
- Initialize the Slice and export it
- Configure the requirements mentioned above.
- Then export the generated Actions creators and Reducers functions.
“Redux requires that we write all state updates immutably, by making copies of data and updating the copies. However, Redux Toolkit’s
createSlice
andcreateReducer
APIs use Immer inside to allow us to write “mutating” update logic that becomes correct immutable updates.”
Here’s their counter slice example:
import { createSlice } from '@reduxjs/toolkit'
export const counterSlice = createSlice({
name: 'counter',
initialState: {
value: 0,
},
reducers: {
increment: (state) => {
// Redux Toolkit allows us to write "mutating" logic in reducers. It
// doesn't actually mutate the state because it uses the Immer library,
// which detects changes to a "draft state" and produces a brand new
// immutable state based off those changes.
// Also, no return statement is required from these functions.
state.value += 1
},
decrement: (state) => {
state.value -= 1
},
incrementByAmount: (state, action) => {
state.value += action.payload
},
},
})
// Action creators are generated for each case reducer function
export const { increment, decrement, incrementByAmount } = counterSlice.actions
export default counterSlice.reducer
Add the Slice to the Store
Import the slice’s reducer and add it to the store.
To do this, go back to store.js
and define a reducer field, which is an object containing all the reducers.
With the following the convention : reducerName: reducerFunction
.
Example:
import { configureStore } from '@reduxjs/toolkit'
import { cookerSlice } from '../features/cooker/cookerSlice'
export default configureStore({
reducer: {
cooker: cookerSlice.reducer,
},
})
Using State and Actions in Components
Now that everything’s set up, we can read from the store and dispatch actions.
- To read from the store use
useSelector
hook. - To dispatch action use the
useDispatch
hook. Create a React component and and use these hooks accordingly to read and update state. For example, here’s theircounter.js
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { decrement, increment } from './counterSlice'
import styles from './Counter.module.css'
export function Counter() {
const count = useSelector((state) => state.counter.value)
const dispatch = useDispatch()
return (
<div>
<div>
<button
aria-label="Increment value"
onClick={() => dispatch(increment())}
>
Increment
</button>
<span>{count}</span>
<button
aria-label="Decrement value"
onClick={() => dispatch(decrement())}
>
Decrement
</button>
</div>
</div>
)
}
Breakdown:
- All the imports, including the reducers from the Slice and Redux hooks.
- Assign the hooks to constants for easier use.
- Build the component that returns JSX
- When the button clicks, using the
onClick
event handler, we dispatch an action usingdispacth(increment)
ordispacth(increment)
.
The dispatched action is then reduced by the corresponding Reducer function in counterSlice.js
, and the component will re-render with the new state.
Summary
- Create a Redux store with
configureStore
configureStore
accepts areducer
function as a named argumentconfigureStore
automatically sets up the store with good default settings
- Provide the Redux store to the React application components
- Put a React Redux
<Provider>
component around your<App />
- Pass the Redux store as
<Provider store={store}>
- Put a React Redux
- Create a Redux “slice” reducer with
createSlice
- Call
createSlice
with a string name, an initial state, and named reducer functions - Reducer functions may “mutate” the state using Immer
- Export the generated slice reducer and action creators
- Call
- Use the React Redux
useSelector/useDispatch
hooks in React components- Read data from the store with the
useSelector
hook - Get the
dispatch
function with theuseDispatch
hook, and dispatch actions as needed
- Read data from the store with the