Everything About Redux in React: Definition, Principles and Detailed Examples

VnnTools

Are you a React developer? Have you heard about Redux and felt confused? Or are you building a React application and starting to "go crazy" because you have to pass props through dozens of different components?

If the answer is "Yes", then you've come to the right place.

State in ReactJS: Concepts, usage and detailed examples

This article will help you decode everything about Redux and its combination with ReactJS. We'll go from the most basic concepts together, explore why Redux was born, how it works, and most importantly, when you really need it.

Let's start this journey!

1. The Nightmare Called "Prop Drilling" and the Birth of Redux

Imagine you're building a large application, such as an e-commerce website. You have user information (name, avatar, shopping cart) in the root App component. Now, you want to display the user's name in the Header and the number of products in the cart in a MiniCart component deep inside the Header.

Following the conventional React approach, what would you have to do?

  1. Pass userInfo from App down to HomePage.
  2. Pass userInfo from HomePage down to Header.
  3. Header uses userInfo.name and continues to pass userInfo.cart down to the MiniCart component.

This long chain of data passing through multiple intermediate component layers that don't even need it is called "Prop Drilling".

This is exactly the big problem that Redux was born to solve.

What is Redux? The Easiest Definition

Redux is a predictable state management library for JavaScript applications. It's not part of React, but an independent library that can be used with React, Angular, Vue, or even Vanilla JS.

Think of Redux as a "shared warehouse" for your entire application. Instead of each component keeping its own state and passing it to each other in a chaotic way, all important state (such as user information, theme settings, product data...) will be stored in a single place called the Store.

Any component, no matter how deep in the component tree, can "connect" directly to this "warehouse" to get the data it needs or request data changes without having to go through intermediate components.

Part 2: Three "Core" Concepts of Redux

To understand Redux, you need to master 3 core concepts. They form a very clear and debuggable unidirectional data flow.

1. Store

This is the heart of Redux. The Store is a massive JavaScript object containing the entire application state.

  • Unique: Your entire application has only ONE Store. This is called "Single Source of Truth".
  • Read-only: You are never allowed to directly change state in the Store. For example: store.state.user = 'new user' is FORBIDDEN.
  • How to change: The only way to change state is to send an "Action".

2. Actions

If you want to change state in the Store, you must "send a request". An Action is exactly that request.

  • A plain JavaScript object: An Action must have a type property to describe the action, for example: 'auth/loginSuccess', 'cart/addProduct'.
  • Can contain accompanying data (payload): Besides type, an Action can carry data necessary for state changes. This data is usually placed in the payload property.

Example of an Action:

// Action to add a product to cart
{
  type: 'cart/addProduct',
  payload: {
    productId: 'prod_123',
    name: 'Laptop ABC',
    price: 20000000
  }
}

3. Reducers

When an Action is sent (dispatch), Redux will pass it to the Reducer.

  • A pure function: Reducer takes 2 parameters: (currentState, action) and returns a newState.
  • Never change old state: Instead of modifying the current state, Reducer must create a copy of the state, make changes on that copy, and return the new copy. This is the immutability principle.
  • Process based on action.type: Inside Reducer, you'll use switch...case or if...else to check action.type and decide how to update state.

Example of a simple Reducer:

const initialState = {
  items: [],
  totalAmount: 0,
}

function cartReducer(state = initialState, action) {
  switch (action.type) {
    case 'cart/addProduct':
      // Create a new copy of state
      const newState = {
        ...state,
        // Add new product to items array
        items: [...state.items, action.payload],
        // Update total amount
        totalAmount: state.totalAmount + action.payload.price,
      }
      // Return new state
      return newState
    default:
      // If action doesn't match, return current state
      return state
  }
}

Complete workflow:

  1. UI Event: User clicks "Add to Cart" button.
  2. Dispatch Action: Component calls dispatch() function to send an Action { type: 'cart/addProduct', payload: {...} }.
  3. Reducer processes: Store receives Action and passes it to cartReducer. This Reducer processes and returns a new cart state.
  4. Store updates: Store replaces old state with new state that Reducer just returned.
  5. UI updates: React components that are "listening" to cart changes will automatically re-render with new data.

Part 3: React Redux - The Perfect Bridge

As mentioned, Redux is an independent library. To connect it with React effectively, we use the react-redux library. This library provides hooks and components that make interaction easy.

  • <Provider store={store}>: A component used to wrap your entire application (<App />). It helps all child components access the Redux store.
  • useSelector(): A hook that allows components to "read" or "get" data from store. It takes a function to select the piece of state that the component needs.
  • useDispatch(): A hook that returns the store's dispatch function. You use this function to send Actions.

Part 4: Redux Toolkit (RTK) - The Upgraded Version

Many developers find "classic" Redux quite verbose and have to write a lot of repetitive code (boilerplate). Recognizing this, the Redux team created Redux Toolkit (RTK).

Redux Toolkit is the official toolkit, recommended for developing Redux applications. It helps simplify and speed up the Redux coding process.

RTK solves the problems of old Redux by:

  • Reducing boilerplate code: With the createSlice function, you can define Reducer and Actions in the same file concisely.
  • Simple Store configuration: configureStore automatically sets up necessary things, including Redux DevTools.
  • Built-in ImmerJS integration: Helps you write code that changes state as if you're modifying directly (mutable), but it still ensures immutability behind the scenes.

If you're starting with Redux today, use Redux Toolkit.

// Create Slice with createSlice
import { createSlice } from '@reduxjs/toolkit'

const cartSlice = createSlice({
  name: 'cart',
  initialState: {
    items: [],
    totalAmount: 0,
    isLoading: false,
  },
  reducers: {
    addProduct: (state, action) => {
      // With Immer, you can "modify" state directly
      state.items.push(action.payload)
      state.totalAmount += action.payload.price
    },
    removeProduct: (state, action) => {
      const index = state.items.findIndex(
        (item) => item.id === action.payload.id,
      )
      if (index !== -1) {
        const removedItem = state.items[index]
        state.items.splice(index, 1)
        state.totalAmount -= removedItem.price
      }
    },
    clearCart: (state) => {
      state.items = []
      state.totalAmount = 0
    },
    setLoading: (state, action) => {
      state.isLoading = action.payload
    },
  },
})

// Automatically generate actions
export const { addProduct, removeProduct, clearCart, setLoading } =
  cartSlice.actions

// Automatically generate reducer
export default cartSlice.reducer

Part 5: Pros, Cons and When to Use Redux?

Redux is very powerful, but it's not a "silver bullet" for every project.

Advantages:

  • Predictable: Unidirectional data flow helps you easily know where, when and why state changes.
  • Centralized management: Everything in one place, easy to manage and scale.
  • Excellent debugging: With Redux DevTools, you can "time travel", review each action and state changes.
  • Large ecosystem: Many supporting libraries (redux-persist, redux-saga, redux-thunk...).

Disadvantages:

  • Learning curve: Takes time to understand the concepts clearly.
  • Verbose: Even with RTK, setting up for simple tasks can still take more effort than component internal state.
  • Not for everyone: Using Redux for a small, simple application is "using a butcher knife to kill a chicken".

So when should you use Redux?

  • Large and complex applications: When state is shared by many components not directly related.
  • Application state changes frequently: Need a strict management mechanism.
  • Need advanced debugging features: Like time-travel debugging.
  • Working in large teams: Redux's clear structure helps team members collaborate easily.

Redux Alternatives

  • React Context API: Built into React, good for simple data passing, avoiding prop drilling at small scale.
  • Zustand, Jotai: Modern state management libraries, minimal and less boilerplate than Redux.
  • MobX: Another powerful solution based on Reactive Programming.

Redux is not a scary concept. It's a powerful tool, an excellent architectural solution for the state management problem in large-scale JavaScript applications. By concentrating all state into a single "warehouse" and imposing a unidirectional data flow, Redux brings clarity, predictability, and extraordinary debugging capabilities.

With the birth of Redux Toolkit, using Redux has become simpler and more efficient than ever.

Hopefully through this article, you not only understand "what is Redux in React" but can also confidently decide whether it's suitable for your next project or not.

Good luck on your journey to conquer React and Redux!

Related Posts

State in ReactJS: Concepts, Usage, and Detailed Examples

Learn the concepts, declaration, and usage of State to manage dynamic data in your React application. See detailed guide with examples.

Two-way Binding in React: How It Works & Easy-to-Understand Examples

Detailed guide on two-way binding in React. This article analyzes how it works, explains the differences compared to other frameworks, and provides practical examples.

What is JSX in React? A Comprehensive Guide for Beginners

JSX is a syntax extension for JavaScript that allows you to write HTML-like code in React. This article will help you understand what JSX is, why we need JSX, and how to use it effectively.

What is a React Component? A Detailed Guide for Beginners

Understanding React Components is the key to building modern web application interfaces. Read now to master common component types and how to create your first component.