Intro

React-Redux is the official React bindings layer, it’s a package. One that lets your read from the Redux Store and dispatch to it to update state from within React components.

This is one of three ways to use Redux for React, the other being the more recommended Redux Toolkit.

Installation

The recommended way is to use the official TypeScript template that uses Vite OR creating a Next.js app with the Redux template. I’ll be using the latter.

Commands:

# Vite with our Redux+TS template
# (using the `degit` tool to clone and extract the template)
npx degit reduxjs/redux-templates/packages/vite-template-redux my-app
 
# Next.js using the `with-redux` template
npx create-next-app --example with-redux my-app

Existing React App

install it as a dependency:

# If you use npm:
npm install react-redux
# Or if you use Yarn:
yarn add react-redux

You’ll also need to install Redux and set up a Redux store in your app.

API

Provider

This component makes the Redux Store available to the entire app, similar to React Context. Example:

import React from 'react'
import ReactDOM from 'react-dom/client'
 
import { Provider } from 'react-redux'
import store from './store'
 
import App from './App'
 
// As of React 18
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(
  <Provider store={store}>
    <App />
  </Provider>,
)

Hooks

This package has a pair of custom hooks for interacting with the state Store.

  1. useSelector reads a value from the store state and subscribes to updates.
  2. useDispatch returns the store’s dispatch method to let you dispatch actions.

==// Make sure you’re accessing with the correct structure when using useSelector!== Counter component example:

import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import {
  decrement,
  increment,
  incrementByAmount,
  incrementAsync,
  selectCount,
} from './counterSlice'
import styles from './Counter.module.css'
 
export function Counter() {
  const count = useSelector(selectCount)
  const dispatch = useDispatch()
 
  return (
    <div>
      <div className={styles.row}>
        <button
          className={styles.button}
          aria-label="Increment value"
          onClick={() => dispatch(increment())}
        >
          +
        </button>
        <span className={styles.value}>{count}</span>
        <button
          className={styles.button}
          aria-label="Decrement value"
          onClick={() => dispatch(decrement())}
        >
          -
        </button>
      </div>
      {/* omit additional rendering output here */}
    </div>
  )
}

Slices

A slice is a self-contained unit (is a JS module) that encapsulates a specific portion or domain of your Store’s state, hence the name “slice”… It’s done this to be more modular, and is part of the ToolKit.

To create a Slice, we use the createSlice function; which automatically generates action creators and more for us, less code. But need to pass it it an object containing name, initialState, and reducers fields. The reducers field is an object containing the reducer functions’ definitions, one per action. See React-Redux - Tutorial for an example.

Example code:

import { createSlice } from "@reduxjs/toolkit";
 
export const counterSlice = createSlice({
    name: "counter",
    initialState: {
        value: 0,
    },
    reducers: {
        increment: (state) => {
            state.value += 1;
        },
        decrement: (state) => {
            state.value -= 1;
        },
    }
});
 
export const { increment, decrement } = counterSlice.actions;
export default counterSlice.reducer;

Passing Values to Reducer

Take increment for example, it expects the state, that much is obvious, but say you want to pass it a value to add to or replace the state, use action. Example:

reducers:{
	myReducer: (state, action) =>{
		state = action.payload
	}
}

In this example the state’s replaced by the new value passed as the action’s payload by the dispatch function.


References