Setting Up and Configuring the Redux Store in a React Application

This article is divided into below sub-topics:

State Management Overview

Redux Toolkit is a powerful library that simplifies the process of managing state in your application. It provides a set of tools and best practices to help you write more efficient and maintainable Redux code. The main benefits of using Redux Toolkit include:

  • Less Boilerplate: Redux Toolkit reduces the amount of boilerplate code you need to write.
    Simplified Configuration: It includes utilities to simplify store setup and configuration.
  • Enhanced Developer Experience: Tools like Redux DevTools and built-in middleware support improve the development process.
  • Improved Performance: Built-in memorization and other optimizations help improve application performance.

Setting Up the Store

Setting up Redux in a React application involves below steps to ensure efficient state management. Here we will walk through configuring the Redux store, including creating a Redux slice, an async thunk, and combining slices in the root reducer.

  1. Create a Redux Slice: A slice is a collection of Redux reducer logic and actions for a single feature of your application. Create a slice file in store folder (e.g., counterSlice.js):
    import { createSlice } from '@reduxjs/toolkit';

    const counterSlice = createSlice({
      name: 'counter',
      initialState: { value: 0 },
      reducers: {
        increment: (state) => {
          state.value += 1;
        },
        decrement: (state) => {
          state.value -= 1;
        },
      },
    });

    export const { increment, decrement } = counterSlice.actions;
    export default counterSlice.reducer;

  2. Create an Async Thunk: Create a file in your store folder, for example, postSlice.js:
    import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
    import axios from 'axios';

    const BASE_URL = 'https://jsonplaceholder.typicode.com/posts';

    const initialState = {
      posts: [],
      status: 'idle',
      error: null,
    };

    export const fetchPosts = createAsyncThunk('posts/fetchPosts', async () => {
      const response = await axios.get(BASE_URL);
      console.log(response.data);
      return response.data;
    });

    const postsSlice = createSlice({
      name: 'posts',
      initialState,
      reducers: {
        // normal reducer functions go here
      },
      extraReducers: (builder) => {
        builder
          .addCase(fetchPosts.pending, (state) => {
            state.status = 'loading';
          })
          .addCase(fetchPosts.fulfilled, (state, action) => {
            state.status = 'succeeded';
            state.posts = state.posts.concat(action.payload);
          })
          .addCase(fetchPosts.rejected, (state, action) => {
            state.status = 'failed';
            state.error = action.error.message;
          });
      },
    });

    export default postsSlice.reducer;

     

  3. Combine Slices in the Root Reducer: Open store folder and add created reducer in store.js
    const rootReducer = combineReducers({
    // Add Other reducers
    counter: counterReducer,
    post: postReducer
    });

     

For more information on setting up store refer to redux-toolkit documentation.


Usage of the Store

Once the Redux store is configured and integrated into your React application, you can interact with it using 'useSelector' and 'useDispatch' hooks provided by 'react-redux'.  The 'useSelector'hook allows you to extract state from the Redux store, while the 'useDispatch' hook is used to dispatch actions.

  • Access State:
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement } from './counterSlice';

const Counter = () => {
  const count = useSelector((state) => state.counter.value);
  const dispatch = useDispatch();

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

export default Counter;
  • Dispatch Actions: 
import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { fetchPosts } from './postsSlice';

const PostsList = () => {
  const dispatch = useDispatch();
  const posts = useSelector((state) => state.posts.posts);
  const status = useSelector((state) => state.posts.status);
  const error = useSelector((state) => state.posts.error);

  useEffect(() => {
    if (status === 'idle') {
      dispatch(fetchPosts());
    }
  }, [status, dispatch]);

  let content;

  if (status === 'loading') {
    content = <p>Loading...</p>;
  } else if (status === 'succeeded') {
    content = posts.map((post) => (
      <div key={post.id}>
        <h3>{post.title}</h3>
        <p>{post.body}</p>
      </div>
    ));
  } else if (status === 'failed') {
    content = <p>{error}</p>;
  }

  return (
    <section>
      <h2>Posts</h2>
      {content}
    </section>
  );
};

export default PostsList;

 

 

Related Topics

Understanding React Folder Structure
Working with Form Builder
Using Reusable Components
Creating Reusable Components in React

 

Was this article helpful?
0 out of 0 found this helpful

Comments

0 comments

Please sign in to leave a comment.