Instagram
youtube
Facebook
Twitter

Redux Basics

Introduction

Redux is a popular JavaScript library used for managing and centralizing application state. It provides a predictable, centralized state container that helps you build applications that behave consistently. While React’s built-in state management is powerful, it can become challenging to manage complex, large-scale applications as they grow. Redux is especially useful for applications with dynamic or shared data and provides a clear pattern for handling global state.

In this lesson, you’ll learn:

  • What Redux is and why it’s useful for state management
  • The core concepts of Redux, including actions, reducers, and the store
  • How to set up Redux in a React application

What is Redux?

Redux is a state management library that centralizes the application’s state in a single store. In Redux, data flow is unidirectional and predictable, making it easier to track, debug, and manage the application's state. Redux is not tied to any specific framework and can be used with various JavaScript libraries, but it’s most commonly used with React.

Key principles of Redux include:

  1. Single Source of Truth: All application state is kept in a single store.
  2. State is Read-Only: The only way to modify state is by dispatching actions, ensuring consistency.
  3. Changes are Made with Pure Functions: Reducers are pure functions that take the previous state and an action and return the next state.

When to Use Redux

Redux is ideal for applications where:

  • The state needs to be shared among multiple components.
  • The application’s state changes frequently.
  • Data from different parts of the app needs to be updated based on user interactions.
  • Managing complex state or performing actions based on asynchronous data (e.g., fetching data from an API) is required.

If your app has minimal shared or global state, using Redux may be unnecessary overhead, and the Context API or React’s local state may be sufficient.


Core Concepts of Redux

The Redux library is based on several key concepts:

  1. Store: The centralized location where the entire application’s state is managed.
  2. Action: An object describing a change or event in the application, containing a type and optional payload.
  3. Reducer: A pure function that takes the current state and an action and returns the next state.
  4. Dispatch: A function used to send actions to the store to trigger state changes.
  5. Selector: A function used to retrieve specific data from the Redux store.

Setting Up Redux in a React Application

To use Redux in a React app, you’ll need to install the Redux and React-Redux libraries. React-Redux provides bindings for connecting Redux with React components.

Step 1: Installing Redux and React-Redux

npm install redux react-redux

Creating a Basic Redux Setup

In this section, we’ll create a simple Redux setup for managing a counter application.


Step 2: Creating Actions

Actions are objects that describe events or changes in the application. Every action has a type property that indicates the type of action being performed, and it may include a payload with additional data.

Example: Defining Action Types and Action Creators

Create an actions.js file to define your action types and creators.

// actions.js

// Action Types
export const INCREMENT = 'INCREMENT';
export const DECREMENT = 'DECREMENT';

// Action Creators
export const increment = () => ({
  type: INCREMENT,
});

export const decrement = () => ({
  type: DECREMENT,
});

In this example:

  • INCREMENT and DECREMENT are action types.
  • increment and decrement are action creators, functions that return an action object.

Step 3: Creating Reducers

Reducers are pure functions that handle the state changes based on the dispatched actions. They take the current state and an action as arguments and return the next state.

Example: Creating a Reducer

Create a reducer.js file to define your reducer.

// reducer.js

import { INCREMENT, DECREMENT } from './actions';

const initialState = {
  count: 0,
};

function counterReducer(state = initialState, action) {
  switch (action.type) {
    case INCREMENT:
      return {
        ...state,
        count: state.count + 1,
      };
    case DECREMENT:
      return {
        ...state,
        count: state.count - 1,
      };
    default:
      return state;
  }
}

export default counterReducer;

In this example:

  • counterReducer listens for INCREMENT and DECREMENT actions.
  • Based on the action type, it updates the count value and returns the new state.

Step 4: Creating the Redux Store

The store is the centralized place where all of the application’s state lives. To create a store, use Redux’s createStore() function, which takes the reducer as an argument.

Example: Setting Up the Store

// store.js

import { createStore } from 'redux';
import counterReducer from './reducer';

const store = createStore(counterReducer);

export default store;

In this example:

  • createStore(counterReducer) creates a Redux store using the counterReducer we defined earlier.

Connecting Redux to React

Now that we have the store, actions, and reducer set up, we need to connect Redux to React components using React-Redux’s <Provider /> component and useSelector and useDispatch hooks.

Step 5: Providing the Redux Store

Wrap your app in the Redux <Provider /> component and pass the store as a prop. This makes the store accessible to all components within the app.

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

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

In this example:

  • The <Provider /> component is provided by react-redux and allows access to the Redux store throughout the app.

Step 6: Accessing State with useSelector

The useSelector hook allows components to read data from the Redux store.

Example: Using useSelector to Access State

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

const CounterDisplay = () => {
  const count = useSelector((state) => state.count);

  return <h1>Count: {count}</h1>;
};

export default CounterDisplay;

In this example:

  • useSelector takes a function that receives the store’s state and returns the specific part of the state that we need (count in this case).

Step 7: Dispatching Actions with useDispatch

The useDispatch hook provides the dispatch function, allowing components to send actions to the Redux store to trigger state changes.

Example: Using useDispatch to Send Actions

import React from 'react';
import { useDispatch } from 'react-redux';
import { increment, decrement } from './actions';

const CounterControls = () => {
  const dispatch = useDispatch();

  return (
    <div>
      <button onClick={() => dispatch(increment())}>Increment</button>
      <button onClick={() => dispatch(decrement())}>Decrement</button>
    </div>
  );
};

export default CounterControls;

In this example:

  • useDispatch provides the dispatch function, which allows you to trigger actions like increment() and decrement() when the buttons are clicked.

Complete Example: Counter App with Redux

Here’s how all the parts fit together in a simple Counter app:

// App.js

import React from 'react';
import CounterDisplay from './CounterDisplay';
import CounterControls from './CounterControls';

const App = () => (
  <div>
    <CounterDisplay />
    <CounterControls />
  </div>
);

export default App;

In this example:

  • CounterDisplay displays the current count using useSelector.
  • CounterControls allows incrementing or decrementing the count using useDispatch.

Conclusion

In this lesson, you’ve learned:

  • The basics of Redux, including actions, reducers, and the store
  • How to set up Redux in a React application
  • How to use useSelector and useDispatch to connect components to the Redux store

Redux is a powerful tool for managing complex, shared state in React applications, especially as your app grows. In the next lesson, you’ll learn about middleware in Redux, including how to handle asynchronous actions with tools like redux-thunk and redux-saga.