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.
- 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 }
});
- 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;
}
}
- 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 }]
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)