Redux State Management Examples and React Hooks Performance

Redux Task Store Implementation

1. Setup and Initial State

Import createStore from Redux. Note: In modern Redux Toolkit, this function is deprecated in favor of configureStore.

const { createStore } = require('redux'); // Or 'import { createStore } from 'redux';'
const initialState = { tasks: [] };
  

2. Action Types & Creators

Define actions for adding and removing tasks.

const ADD_TASK = 'ADD_TASK';
const REMOVE_TASK = 'REMOVE_TASK';

function addTask(task) { // task: { id, description }
  return { type: ADD_TASK, payload: task };
}

function removeTask(taskId) { // taskId: number
  return { type: REMOVE_TASK, payload: taskId };
}
  

3. Task Reducer Logic

The reducer handles state transitions immutably.

function taskReducer(state = initialState, action) {
  switch (action.type) {
    case ADD_TASK:
      return { ...state, tasks: [...state.tasks, action.payload] }; // Add new task to a new array
    case REMOVE_TASK:
      return { ...state, tasks: state.tasks.filter(task => task.id !== action.payload) }; // Filter out task by id
    default:
      return state; // Return current state if action is unknown
  }
}
  

4. Store Creation and Dispatching

Create the store and subscribe to changes.

const store = createStore(taskReducer);

// Listener for state changes
const unsubscribe = store.subscribe(() => {
  console.log('--- Store Updated ---');
  console.log('New State:', JSON.stringify(store.getState(), null, 2));
  console.log('---------------------');
});

console.log('Initial State:', JSON.stringify(store.getState(), null, 2));

console.log('\nDispatching: addTask({ id: 1, description: "Write report" })');
store.dispatch(addTask({ id: 1, description: 'Write report' }));

console.log('\nDispatching: addTask({ id: 2, description: "Attend meeting" })');
store.dispatch(addTask({ id: 2, description: 'Attend meeting' }));

console.log('\nDispatching: removeTask(1)');
store.dispatch(removeTask(1)); // Removes task with id 1

unsubscribe(); // Stop listening to store updates
  

Simple Redux Bank Account Example

A second example demonstrating a simple withdrawal mechanism.

const redux = require('redux');
const createStore = redux.createStore;

function withdraw(){
    return{
        type: "Withdraw_Money",
        payload: 50
    }
}

const initialState = {
    amount: 1000
}

const reducer = (prevState=initialState, action) => {
    switch(action.type){
        case "Withdraw_Money": 
            return {
                ...prevState,
                amount: prevState.amount - action.payload
            }
        default:
            return prevState
    }
}

const store = createStore(reducer);

console.log("Initial state: ", store.getState());

const unsubscribe = store.subscribe(()=>{
    console.log("Updated store: ", store.getState())
})

store.dispatch(withdraw())
store.dispatch(withdraw())
store.dispatch(withdraw())

unsubscribe();
store.dispatch(withdraw());
  

React Component: Product Dashboard with Performance Hooks

This React component fetches products, handles search filtering, and utilizes useMemo and useCallback for optimization.

import React, { useState, useEffect, useMemo, useRef, useCallback } from 'react';
import axios from 'axios'; // Correct: import axios directly

function ProductDashboard() {
  // State for all products fetched from API
  const [allProducts, setAllProducts] = useState([]);
  // State for the current search term entered by the user
  const [searchTerm, setSearchTerm] = useState('');
  // State for loading status
  const [loading, setLoading] = useState(false);
  // State for error messages
  const [error, setError] = useState(null);

  // 1. Fetch product data from a remote API
  useEffect(() => {
    const fetchData = async () => {
      setLoading(true);
      setError(null);
      try {
        // Use the public API: https://fakestoreapi.com/products
        const response = await axios.get('https://fakestoreapi.com/products');
        setAllProducts(response.data || []); // Ensure it's an array
      } catch (err) {
        setError(err.message || 'Failed to fetch products. Please try again.');
        console.error("Failed to fetch products:", err);
      } finally {
        setLoading(false);
      }
    };
    fetchData();
  }, []); // Empty dependency array to run once on mount

  // 3. Enhance UX using useRef: Autofocus search input
  const searchInputRef = useRef(null);
  useEffect(() => {
    if (searchInputRef.current) {
      searchInputRef.current.focus();
    }
  }, []); // Focus on mount

  // Handler for search input changes (updates searchTerm state)
  const handleSearchInputChange = useCallback((event) => {
    setSearchTerm(event.target.value);
  }, []); // setSearchTerm is stable, so [] is fine.

  // 5. Optimize filtering logic using useCallback:
  // Memoize the actual filtering function used inside useMemo for filteredProducts
  const filterLogic = useCallback(
    (product) => {
      // Ensure product.title exists and is a string before calling toLowerCase
      if (typeof product.title !== 'string') {
        return false;
      }
      return product.title.toLowerCase().includes(searchTerm.toLowerCase());
    },
    [searchTerm] // This callback depends only on searchTerm
  );

  // 4. Use useMemo for performance: Create a memoized filteredProducts array
  const filteredProducts = useMemo(() => {
    if (!searchTerm.trim()) {
      // If search term is empty or only whitespace, show all products
      return allProducts;
    }
    return allProducts.filter(filterLogic);
  }, [allProducts, searchTerm, filterLogic]); // Recalculate if these change

  // 4. Use useMemo for performance: Create a memoized variable totalProducts to count the number of products
  const totalProductsCount = useMemo(() => allProducts.length, [allProducts]);

  // 6. Render Output
  return (
    

Product Dashboard

{/* Search input box with autofocus */}

{/* Handle loading state */} {loading &&

Loading products…

}

{/* Handle error state */} {error &&

Error: {error}

}

{/* Display content only if not loading and no error */} {!loading && !error && ( <> {/* Text showing: Total Products: X | Filtered Products: Y */}

Total Products: {totalProductsCount} | Filtered Products: {filteredProducts.length}

{/* A list of product titles that match the search filter */} {allProducts.length > 0 ? ( filteredProducts.length > 0 ? (

  • {filteredProducts.map(product => (
  • {product.title} ))}
) : (

{searchTerm ? ‘No products match your search.’ : ‘No products found.’}

) ) : (

No products available to display.

)} > )}

); }

export default ProductDashboard;