DEV Community

aravind_akay
aravind_akay

Posted on

How redux works in simple terms

If you’ve ever built a React app, you know that passing data between components can feel like playing a stressful game of "telephone." One component tells its parent, who tells the grandparent, who finally tells the cousin.

Redux fixes this by creating a "Single Source of Truth." Instead of data being scattered everywhere, it lives in one central vault.

The Redux Coffee Shop Analogy
To understand Redux, imagine a coffee shop:

The Store (The Vault): This is the giant ledger where the shop keeps track of everything: how many beans are left, the list of orders, and who is working.

The Action (The Customer's Order): A customer doesn't just walk behind the counter and grab a latte. They "order" it. An action is a plain object that describes what happened.

Example: { type: 'ADD_TODO', text: 'Buy Milk' }

The Reducer (The Barista): The barista is the only one allowed to update the ledger. They take the current state of the shop and the customer's order, then they create a new version of the ledger.

The Dispatch (The Cashier): The cashier takes your order and hands it to the barista. In Redux, dispatch is the function that sends your action to the store.

Seeing it in Code: A Simple Todo App
Let’s look at how this looks in a real JavaScript environment.

  1. Define the Actions First, we define what can actually happen in our app. We want to add a task and toggle whether it's finished.
// Actions
const ADD_TODO = 'ADD_TODO';
const TOGGLE_TODO = 'TOGGLE_TODO';

// Action Creators
const addTodo = (text) => ({
  type: ADD_TODO,
  payload: { text, completed: false }
});
Enter fullscreen mode Exit fullscreen mode
  1. The Reducer (The Brain) The reducer decides how the state changes. Crucial Rule: Reducers never change the old state; they always return a brand new copy of it.
const initialState = [];

function todoReducer(state = initialState, action) {
  switch (action.type) {
    case ADD_TODO:
      // We return a NEW array with the old items + the new one
      return [...state, action.payload];

    case TOGGLE_TODO:
      return state.map((todo, index) => {
        if (index === action.index) {
          return { ...todo, completed: !todo.completed };
        }
        return todo;
      });

    default:
      return state;
  }
}
Enter fullscreen mode Exit fullscreen mode
  1. The Store (The Home) Finally, we bring it all together.
import { createStore } from 'redux';

const store = createStore(todoReducer);

// Let's add a todo!
store.dispatch(addTodo('Learn Redux today'));

console.log(store.getState()); 
// Output: [{ text: 'Learn Redux today', completed: false }]
Enter fullscreen mode Exit fullscreen mode

Why go through all this trouble?
You might think, "Why not just use a simple variable?"

As your app grows to include login screens, shopping carts, and user profiles, having a predictable "Store" makes debugging a breeze. If something goes wrong, you can look at the history of Actions to see exactly when and why the data changed. It’s like having a "black box" flight recorder for your website.

Summary
Store: Where your data lives.

Action: A note saying what you want to change.

Reducer: The logic that performs the change.

Dispatch: The trigger that sends the note to the logic.

Happy coding! If you found this helpful, feel free to share it.

Top comments (0)