January 30, 2024
react.js - redux - state management
5 minutes

React Redux Fundamentals

Redux is a state management library, similar to Vuex/Pinia in Vue. It uses reducers to manage application state.

Redux in React

Redux is a state management library, similar to Vuex/Pinia in Vue. It uses reducers to manage application state.

This page is useful to remember some concepts about Redux. I written it while I was studying Redux in React, and I intend to visit here to remember something if I forget.

Get Data

  • useSelector - get data from the store

Post Data

  • useDispatch - dispatch an action to the store

Action

There are 2 attributes that we need to pass to dispatch an action, and it's the same thing that we will receive to treat in reducers.

  • type - the type of action that we want to dispatch, describes the nature of the action, indicating the event triggering it.
  • payload - the data that we want to pass to the reducer, e.g., email and password for a login

NOTE

Updates to a reducer trigger a reactive behavior, causing components using the updated data to re-render.


Get Started (without Redux toolkit)

Setup

  1. In any React project, install the following packages:
yarn add -D redux react-redux
  1. Create a store file, and use the createStore function to create a store.
// store.js
import { createStore } from 'redux'
import rootReducer from './rootReducer'

export default createStore(rootReducer)
  1. Create a root reducer file, and use the combineReducers function to combine all reducers.
// rootReducer.js
import { combineReducers } from 'redux'
import userReducer from './user/reducer'

const rootReducer = combineReducers({
  // here we can add any number of reducers as we need
  userReducer
})

export default rootReducer
  1. Create a reducer file, and use the createReducer function to create a reducer.
// user/reducer.js
const initialState = {
    currentUser: null
}

const userReducer = (state = initialState, action) => {
    switch (action.type) {
        case 'user/login':
            return {
                ...state,
                currentUser: action.payload
            }
        case 'user/logout':
            return {
                ...state,
                currentUser: null
            }
        default:
            return state
    }
}

export default userReducer
  1. Provide the redux to whole application. We need to add it to the root component.
// app/page.jsx
import { Provider } from 'react-redux'
import store from './redux/store'

const App = () => {
    return (
        <Provider store={store}>
            <div>...</div>
        </Provider>
    )
}

After that, we can use the useSelector and useDispatch hooks to get and post data to the store.

Get Data

Use reducer in any place of your app.

// components/navbar.jsx
import { useSelector } from 'react-redux'

const Navbar = () => {
    const { currentUser } = useSelector(rootReducer => rootReducer.userReducer)
    
    return (
        <>
            {currentUser && <div>{currentUser.name}</div>}
        </>
    )
}

Post Data

Use dispatch in any place of your app.

// components/login.jsx
import { useDispatch } from 'react-redux'

const Login = () => {
    const dispatch = useDispatch()
    
    const handleLogin = () => {
        dispatch({
            type: 'user/login',
            payload: {
                email: 'john-doe@email.com',
                password: '123456'
            }
        })
    }

    return (
        <>
            <button onClick={ handleLogin }>Login</button>
        </>
    )
}

Selectors

Selectors are functions that we can use to get data from the store. It's useful to avoid repeating the same code in different places of the app. It can be useful to apply some logic like .map, .filter, and etc.

// user/selectors.js

export const selectCurrentUser = state => state.userReducer.currentUser
// components/navbar.jsx

import { useSelector } from 'react-redux'

import { selectCurrentUser } from './user/selectors'

const Navbar = () => {
    const currentUser = useSelector(selectCurrentUser)
    
    return (
        <>
            {currentUser && <div>{currentUser.name}</div>}
        </>
    )
}