DEV Community

Abhay Singh Kathayat
Abhay Singh Kathayat

Posted on

Mastering Redux Basics: A Complete Guide to State Management in React

Redux Basics: A Detailed Explanation with Code Examples

Redux is a state management library used widely with JavaScript applications, especially with React. It provides a centralized store for the state of your app, making it easier to manage and debug, especially in large and complex applications. Redux follows a unidirectional data flow and ensures that state changes happen in a predictable manner, making it easier to understand how your app works.

Let's break down the Redux basics step by step, explaining each concept with code examples.


1. What is Redux?

Redux is a predictable state container for JavaScript apps. It helps you manage the state of your app in a centralized way, making it easier to debug and scale.

Core Principles of Redux:

  • Single Source of Truth: The whole state of the application is stored in a single object (the store), making it easy to track and manipulate.
  • State is Read-Only: The only way to change the state is by dispatching an action.
  • Changes are Made with Pure Functions: State is modified by reducers, which are pure functions that specify how the state changes in response to an action.

2. Core Concepts of Redux

Redux relies on the following key components:

1. Action

An action is a plain JavaScript object that describes an event or an action that has occurred in the application. Each action must have a type property, which describes the action being performed.

Action Example:

// actions.js
export const increment = () => ({
  type: 'INCREMENT'
});

export const decrement = () => ({
  type: 'DECREMENT'
});
Enter fullscreen mode Exit fullscreen mode
  • Here, increment and decrement are action creators. They return action objects with a type field. The type property tells Redux how to handle the action in the reducer.

2. Reducer

A reducer is a pure function that takes the current state and an action, then returns a new state. Reducers are the functions that specify how the state should change in response to an action. They should be pure functions, meaning they don’t modify the original state but return a new state object.

Reducer Example:

// reducer.js
const initialState = {
  count: 0
};

const 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;
Enter fullscreen mode Exit fullscreen mode
  • In the example above:
    • The initial state is defined with a count of 0.
    • The reducer listens for actions INCREMENT and DECREMENT and updates the count state accordingly.
    • The return { ...state, count: state.count + 1 } line creates a new object to maintain immutability and update the state.

3. Store

The store holds the entire state of your application. The store is created using the createStore method from Redux, and it is where the application’s state lives. The store also provides methods to dispatch actions and subscribe to changes in the state.

Store Example:

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

const store = createStore(counterReducer);

export default store;
Enter fullscreen mode Exit fullscreen mode
  • The store is created by passing the counterReducer to createStore.
  • Now, the state of the application is managed by Redux, and any changes to the state will go through the reducer.

3. Connecting Redux with React

React components need to interact with the Redux store to get the state and dispatch actions. React-Redux, a separate library, is used to connect React with Redux. It provides hooks like useSelector to access the store’s state and useDispatch to dispatch actions.

Steps to Connect Redux with React:

  1. Wrap your app with the Provider component from react-redux to pass the store to all your components.
  2. Use useSelector to access the state.
  3. Use useDispatch to dispatch actions that modify the state.

4. Setting Up Redux in a React App

Let’s walk through the complete setup to connect Redux with a simple React app.


Step 1: Install Redux and React-Redux

First, you need to install Redux and React-Redux:

npm install redux react-redux
Enter fullscreen mode Exit fullscreen mode

Step 2: Create Actions

In Redux, actions are plain JavaScript objects that describe the change you want to make to the state.

// actions.js
export const increment = () => ({
  type: 'INCREMENT'
});

export const decrement = () => ({
  type: 'DECREMENT'
});
Enter fullscreen mode Exit fullscreen mode
  • The increment and decrement functions are action creators that return action objects.
  • The action object has a type field that describes the action.

Step 3: Create a Reducer

A reducer is a function that takes the current state and an action, and returns a new state.

// reducer.js
const initialState = {
  count: 0
};

const 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;
Enter fullscreen mode Exit fullscreen mode
  • The reducer listens for the INCREMENT and DECREMENT actions and updates the state accordingly.

Step 4: Create the Store

The store is where the state lives. It is created using the createStore method from Redux.

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

const store = createStore(counterReducer);

export default store;
Enter fullscreen mode Exit fullscreen mode
  • We pass the counterReducer to createStore to create a store that will manage the state for our app.

Step 5: Connecting Redux with React

Now, let's connect Redux to our React app using the Provider, useDispatch, and useSelector hooks.

// App.js
import React from 'react';
import { Provider, useDispatch, useSelector } from 'react-redux';
import store from './store';
import { increment, decrement } from './actions';

const Counter = () => {
  const count = useSelector((state) => state.count); // Get count from the store
  const dispatch = useDispatch(); // Get dispatch function to send actions

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

const App = () => {
  return (
    <Provider store={store}> {/* Provide the Redux store to the app */}
      <Counter />
    </Provider>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode
  • Provider: Wraps the entire application, passing the Redux store down to all components.
  • useSelector: Retrieves the current state (count) from the Redux store.
  • useDispatch: Allows you to dispatch actions (increment and decrement).

5. Redux Toolkit (Optional)

To make Redux easier to use, Redux Toolkit simplifies setup by reducing boilerplate code. It offers utilities like createSlice and configureStore to handle common tasks such as creating reducers and configuring the store.

Example Using Redux Toolkit:

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

// Define a slice of state
const counterSlice = createSlice({
  name: 'counter',
  initialState: { count: 0 },
  reducers: {
    increment: (state) => {
      state.count += 1;
    },
    decrement: (state) => {
      state.count -= 1;
    }
  }
});

// Configure store
const store = configureStore({
  reducer: counterSlice.reducer
});

export default store;
Enter fullscreen mode Exit fullscreen mode
  • The createSlice function automatically generates action creators and reducers for you.
  • configureStore simplifies store setup.

6. Best Practices for Using Redux

  • Keep Redux for Global State: Use Redux for managing application-wide state (e.g., user authentication, settings).
  • Use Local State for Simple Components: For smaller state needs (like form inputs), use React's useState instead of Redux.
  • Avoid Direct Mutation: Always return a new object when updating state to ensure immutability.

7. Conclusion

Redux is a powerful tool for managing global state in React applications. By understanding actions, reducers, and the store, you can manage complex state in a predictable way. Using Redux Toolkit can simplify this process further. When used correctly, Redux can make large applications easier to manage, debug, and scale.

With this knowledge, you're now equipped to incorporate Redux into your React applications, ensuring more efficient state management across your app.


Top comments (0)