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 reactThen install the packages for Redux:
npm install @reduxjs/toolkit react-reduxCreating 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
Appcomponent - Import
storewe created and importProviderfromreact-redux - Wrap your App in Provider and pass
storeto 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
createSliceandcreateReducerAPIs 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.reducerAdd 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
useSelectorhook. - To dispatch action use the
useDispatchhook. 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
onClickevent 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
configureStoreconfigureStoreaccepts areducerfunction as a named argumentconfigureStoreautomatically 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
createSlicewith 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/useDispatchhooks in React components- Read data from the store with the
useSelectorhook - Get the
dispatchfunction with theuseDispatchhook, and dispatch actions as needed
- Read data from the store with the