← Back home

Redux

Created: 2025-07-29 | Updated: 2025-07-29

For Redux Toolkit, click here

Preparation

What is Redux? what does Redux do?

Terms and Concepts

State Management

Redux extracts the shared state from the components tree and puts it into a centralized location.

Immutability

React and Redux expect that all state updates are done immutably

Terminology

Actions

Example:

const addTodoAction = {
  type: 'todos/todoAdded',
  payload: 'Buy milk',
};

Redux actions and state should only contain plain JS values like objects, arrays, and primitives. Don't put class instances, functions, Date/Map/Set instances, or other non-serializable values into Redux!.

Action Creators

A function returns an action object:

const addTodo = (text) => {
  return {
    type: 'todos/todoAdded',
    payload: text,
  };
};

Reducers

Example:

const initialState = { value: 0 };

function counterReducer(state = initialState, action) {
  // Check to see if the reducer cares about this action
  if (action.type === 'counter/increment') {
    // If so, make a copy of `state`
    return {
      ...state,
      // and update the copy with the new value
      value: state.value + 1,
    };
  }
  // otherwise return the existing state unchanged
  return state;
}

It is called reducer because it works similar to Array.reduce, like in this example:

const actions = [
  { type: 'counter/increment' },
  { type: 'counter/increment' },
  { type: 'counter/increment' },
];

const initialState = { value: 0 };
type State = typeof initialState;
type Action = (typeof actions)[0];

const counterReducer = (state: State, action: Action) => {
  if (action.type === 'counter/increment') {
    return {
      value: state.value + 1,
    };
  }

  return state;
};

const finalResult = actions.reduce(counterReducer, initialState);
console.log(finalResult);

A Redux store needs to have a single "root reducer" function passed in when it's created

This is how we call all of the slice reducers by hand:

function rootReducer(state = {}, action) {
  return {
    users: usersReducer(state.users, action),
    posts: postsReducer(state.posts, action),
    comments: commentsReducer(state.comments, action),
  };
}

But Redux has a function called combineReducers:

const rootReducer = combineReducers({
  users: usersReducer,
  posts: postsReducer,
  comments: commentsReducer,
});

While using Redux Toolkit we can also pass a reducer function directly as the reducer argument:

const store = configureStore({
  reducer: rootReducer,
});

Store

It is where the state lives.

This example blow shows how to use configureStore from Redux Toolkit, by by passing a reducer. We can use store.getState() to get the current state value:

import { configureStore } from '@reduxjs/toolkit';

const store = configureStore({ reducer: counterReducer });

console.log(store.getState());
// {value: 0}

Dispatch

So we can say dispatch triggers an event, then reducer handles the state updating.

Example:

store.dispatch({ type: 'counter/increment' });

console.log(store.getState());

Or call an action creator to dispatch the action:

const increment = () => {
  return {
    type: 'counter/increment',
  };
};

store.dispatch(increment());

console.log(store.getState());

Selector

A functions that extracts a piece of information from state, so you do not have to repeat the same logic again and again in your application.

const selectCounterValue = (state) => state.value;

const currentValue = selectCounterValue(store.getState());
console.log(currentValue);

Redux Application Data Flow

It is a "one-way data flow".

Initial setup

Updates

References

Redux Essentials, Part 1: Redux Overview and Concepts