Skip to main content

Redux.js

What is Redux?

Imagine your application is a big library. In this library, different people (components) are working on different tasks, like checking out books, adding new books, or updating records.

In a small library, everyone might just talk to each other directly to get things done. But as the library grows, it becomes chaotic—people might lose track of who has which books, or records might get mixed up. It’s hard to keep everything organized.

The Problem

Without a system in place, it’s easy to get confused about what’s happening in the library:

  • Who checked out a book?
  • Who added a new book to the inventory?
  • What books are available right now?

In a similar way, as your application grows, managing the "state" (the data your app uses, like the list of books) becomes harder. Different parts of your app might not know what the other parts are doing, leading to bugs and confusion.

Enter Redux

Redux is like a central librarian who keeps track of everything that happens in the library. This librarian (Redux) has a single book (the store) where they write down all the changes and updates.

Formally, Redux is a popular state management library for JavaScript applications, often used with React. It helps manage the state of your application in a predictable and consistent way, making it easier to understand and debug.

Why Use Redux?

As your application grows in complexity, managing the state (data that your application relies on) can become challenging. Without a clear structure, it’s easy for different parts of your app to get out of sync, leading to bugs and unexpected behavior.

Redux helps by:

  • Centralizing State: All the state is stored in a single place called the "store," making it easy to access and update from anywhere in the app.
  • Predictable State Changes: State updates are handled in a predictable way through "actions" and "reducers," making it easier to track changes and debug issues.
  • Ease of Testing: Redux makes it easier to test your application’s logic by separating state management from the UI components.

Core Concepts of Redux

To understand Redux, it’s essential to get familiar with its core concepts:

1. Store

  • The store is a JavaScript object that holds the entire state of your application.
  • You can think of it as a central database for your app’s state. All components in your app can access the store and get the state they need.

2. Action

  • An action is an object that describes a change or an event that should happen in the application. Actions are the only way to send data to the Redux store.
  • An action must have a type property, which is a string that describes what kind of action it is. It can also have other properties, such as payload, which carries the data needed to perform the action.
const addAction = {
type: 'ADD_TODO',
payload: {
text: 'Learn Redux'
}
};

3. Reducer

  • A reducer is a pure function that takes the current state and an action as arguments, and returns a new state. The reducer is responsible for updating the state based on the action received.
  • Reducers are like event listeners: they listen for specific actions and update the state accordingly.
const initialState = {
todos: []
};

function todoReducer(state = initialState, action) {
switch (action.type) {
case 'ADD_TODO':
return {
...state,
todos: [...state.todos, action.payload]
};
default:
return state;
}
}

4. Dispatch

  • Dispatch is a method that sends an action to the Redux store. When an action is dispatched, the store runs the reducer to update the state.
store.dispatch(addAction);

5. Selector

  • A selector is a function that extracts and returns specific data from the state. This helps components get the exact data they need from the store.
const selectTodos = state => state.todos;

How Redux Works: A Simple Example

Let’s walk through a simple example of how Redux works by building a basic to-do list application.

Step 1: Set Up the Redux Store

First, you need to set up the Redux store where the state of your application will live.

import { createStore } from 'redux';

// Initial state
const initialState = {
todos: []
};

// Reducer function
function todoReducer(state = initialState, action) {
switch (action.type) {
case 'ADD_TODO':
return {
...state,
todos: [...state.todos, action.payload]
};
default:
return state;
}
}

// Create the Redux store
const store = createStore(todoReducer);

Step 2: Dispatch an Action

Next, you’ll want to add a new to-do item to the list. To do this, you dispatch an action.

// Action to add a new to-do
const addAction = {
type: 'ADD_TODO',
payload: {
text: 'Learn Redux'
}
};

// Dispatch the action
store.dispatch(addAction);

Step 3: Access the State

Finally, you can access the updated state from the store to see the changes.

console.log(store.getState());
// Output: { todos: [{ text: 'Learn Redux' }] }

Step 4: Connecting Redux to React

In a React application, Redux is often used alongside React-Redux, a library that provides bindings between React and Redux.

Here’s how you can connect Redux to a React component:

  1. Install React-Redux:

    npm install react-redux

  2. Provider: Wrap your app with the Provider component, which makes the Redux store available to your entire application.

    import React from 'react';
    import ReactDOM from 'react-dom';
    import { Provider } from 'react-redux';
    import { createStore } from 'redux';
    import todoReducer from './reducers';
    import App from './App';

    const store = createStore(todoReducer);

    ReactDOM.render(
    <Provider store={store}>
    <App />
    </Provider>,
    document.getElementById('root')
    );

  3. Connecting a Component: Use the useSelector and useDispatch hooks to connect your React components to the Redux store.

    import React from 'react';
    import { useSelector, useDispatch } from 'react-redux';

    function TodoList() {
    const todos = useSelector(state => state.todos);
    const dispatch = useDispatch();

    const addTodo = () => {
    dispatch({
    type: 'ADD_TODO',
    payload: { text: 'Learn Redux' }
    });
    };

    return (
    <div>
    <button onClick={addTodo}>Add To-Do</button>
    <ul>
    {todos.map((todo, index) => (
    <li key={index}>{todo.text}</li>
    ))}
    </ul>
    </div>
    );
    }

    export default TodoList;

Key Benefits of Using Redux

  1. Predictable State: Because state changes in Redux are centralized and follow strict rules, you can easily predict and track state changes throughout your application.
  2. Ease of Debugging: With Redux, you can log every action that changes the state, making it easier to debug issues in your application.
  3. Consistency: Redux enforces a consistent approach to managing state, which helps maintainable code in large applications.
  4. Ecosystem: Redux has a rich ecosystem of tools and middleware, such as Redux Thunk and Redux Saga, which can handle complex asynchronous operations.

When to use Redux

Use Redux if:

  • Your app has complex state management needs.
  • You need consistent and predictable state across many components.
  • You’re building a large, scalable application.

Don’t use Redux if:

  • Your app is simple with minimal state management needs.
  • State is local to a few components.
  • You want to avoid the added complexity and learning curve.

Conclusion

Redux is a powerful tool for managing state in JavaScript applications, especially as they grow in complexity. By centralizing and standardizing state management, Redux makes it easier to build, debug, and maintain your applications.

In this lesson, we covered the basic concepts of Redux, including the store, actions, reducers, and dispatching. We also walked through a simple example of how to use Redux in a React application. As you continue to work with Redux, you’ll discover many more advanced features and patterns that can help you build robust, scalable applications.


Contributors