Redux for Beginners: Learn Redux Basics with Code Examples

If you‘re learning React, you may have heard of Redux as a way to manage application state. Redux is a popular library that‘s often used in larger, more complex React projects. But what exactly is it, and when should you use it? In this guide, we‘ll break down the basics of Redux for beginners and show you how to get started using it with React.

What is Redux?

Redux is a predictable state container for JavaScript applications. It helps you manage and centralize the state of your app, making it easier to reason about changes and keep everything in sync.

The main idea of Redux is that you have:

  1. A single, centralized store that holds the entire state of your application
  2. Actions that describe state changes
  3. Reducers that specify how the state should update in response to actions
  4. The ability to dispatch actions to update the state

By centralizing your state and standardizing how it can be updated, Redux helps avoid bugs caused by scattered, out-of-sync state changes. It also makes it easier to trace when, where, why and how your app‘s state changed over time.

Redux architecture diagram

When to Use Redux

Redux is not necessary for every app. If your React components can manage their own state without too much complexity, local state is often sufficient. Dan Abramov, a co-author of Redux, has a helpful blog post on when you might not need Redux.

However, there are situations where Redux becomes beneficial:

  • You have large amounts of application state that are needed in many places
  • The app state is updated frequently over time
  • The logic to update that state may be complex, involving multiple asynchronous calls or event sources
  • The app has a medium or large-sized codebase, and might be worked on by many people

According to the 2020 State of JS Survey, Redux is used by 50.4% of respondents, making it the most popular data layer tool.

Chart showing 50.4% usage of Redux in State of JS survey

How Redux Works

To understand Redux, it helps to visualize how data flows through its various parts. Let‘s use an analogy of a bank to make the concepts more relatable.

Imagine the entire state of your application is like a giant vault in a bank. This vault contains various deposit boxes, each holding a piece of state, like user information, posts, settings, etc. This vault is the Redux store – it‘s the single source of truth for all your app‘s data.

Redux store represented as a bank vault

Now, the only way to change something in a safety deposit box is to fill out a deposit or withdrawal slip – you can‘t just reach in and change things directly. In Redux, these slips are called actions. An action is a plain object describing the change, like:

{ type: ‘DEPOSIT‘, amount: 100 }
{ type: ‘WITHDRAW‘, amount: 50 }

To actually make a change, you hand the slip to a bank teller. The teller follows strict instructions on how to process each type of slip. These instructions are the reducer functions in Redux. A reducer takes the current state and an action, and returns the new state:

function bankReducer(state = 0, action) {
  switch (action.type) {
    case ‘DEPOSIT‘:
      return state + action.amount;
    case ‘WITHDRAW‘:
      return state - action.amount;
    default:
      return state;
  }
}

The act of handing the slip to the teller is dispatching an action in Redux. You dispatch an action to tell the store to update:

dispatch({ type: ‘DEPOSIT‘, amount: 100 });

Finally, other parts of your app (like React components) can subscribe to the bank vault to be notified when the balance changes so they can update accordingly.

Setting Up Redux

To use Redux in a React app, you‘ll need to install the redux and react-redux packages:

npm install redux react-redux

Then, create a new file for your Redux store and add the following code:

// store.js
import { createStore } from ‘redux‘;

// Define an initial state
const initialState = {
  balance: 0
};

// Create a reducer
function bankReducer(state = initialState, action) {
  switch(action.type) {
    case ‘DEPOSIT‘:
      return { balance: state.balance + action.amount };
    case ‘WITHDRAW‘:
      return { balance: state.balance - action.amount }; 
    default:
      return state;
  }
}

// Create the store
const store = createStore(bankReducer);

export default store;

Here we define an initial state with a balance of 0, create a reducer function to handle deposits and withdrawals, and use the Redux createStore function to generate the store.

To use this store in a React component, wrap your top-level App component with the Provider from react-redux:

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

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

Now any component in your app can access the Redux store.

Using Redux in React Components

The react-redux library provides a few hooks to let your React components interact with the Redux store.

To read data from the store, use the useSelector hook:

import { useSelector } from ‘react-redux‘;

function Balance() {
  const balance = useSelector(state => state.balance);
  return <div>Balance: {balance}</div>;
}

To dispatch actions to the store, use the useDispatch hook:

import { useDispatch } from ‘react-redux‘;

function DepositForm() {
  const dispatch = useDispatch();

  function handleDeposit(amount) {
    dispatch({ type: ‘DEPOSIT‘, amount });
  }

  return (
    <button onClick={() => handleDeposit(100)}>
      Deposit $100
    </button>
  );
}

Middleware and Async Actions

One of the powerful features of Redux is the ability to add middleware between dispatching an action and when it reaches the reducer. Middleware can intercept, modify, delay, replace or stop actions.

A common use case is handling asynchronous actions, like making an API call. The Redux Thunk middleware lets you write action creators that return a function instead of an action object. This function can perform async logic and dispatch actions when it‘s done:

// An async action creator
function fetchUser(id) {
  return async function(dispatch) {
    const response = await fetch(`/api/users/${id}`);
    const user = await response.json();
    dispatch({ type: ‘USER_LOADED‘, user });
  };
}

To enable middleware like Redux Thunk, you pass it to the createStore function:

import thunk from ‘redux-thunk‘;
import { createStore, applyMiddleware } from ‘redux‘;

const store = createStore(reducer, applyMiddleware(thunk));

Best Practices for Structuring Redux Code

As your app grows, it‘s helpful to follow some conventions for organizing your Redux-related code. Here‘s a typical structure:

src/
  redux/
    actions/
      userActions.js
      postActions.js
    reducers/
      userReducer.js
      postReducer.js
      rootReducer.js
    types/
      userTypes.js
      postTypes.js
    store.js

Some tips:

  • Split up reducers and actions by feature or data domain
  • Use constants for action types to avoid typos and make refactoring easier
  • Combine reducers using Redux‘s combineReducers function

Redux Alternatives and Next Steps

While Redux is very popular, it‘s not the only way to manage state in a React application. Other options include:

  • React‘s built-in Context API and useReducer hook
  • State management libraries like MobX or Recoil
  • GraphQL clients like Apollo that include state management

Ultimately, the right choice depends on the specific needs and scale of your application.

If you do choose to use Redux, there are several additional topics and best practices to learn, such as:

  • Using selector functions to compute derived data
  • Normalizing state shape for better performance and maintainability
  • Implementing undo/redo functionality
  • Writing tests for reducers and async action creators
  • Using the Redux DevTools for debugging

Here are some recommended resources to continue your Redux learning journey:

With a solid understanding of Redux basics under your belt, you‘ll be well-equipped to start using it in your own React projects. As you encounter new challenges and use cases, don‘t hesitate to refer back to the documentation and continue expanding your Redux knowledge. Happy coding!

Similar Posts