Managing State and Side Effects: useState, useReducer, useEffect, and useLayoutEffect

  • Home
  • React JS
  • Managing State and Side Effects: useState, useReducer, useEffect, and useLayoutEffect
Front
Back
Right
Left
Top
Bottom
STATE
Sanjeewa%20RupasingheuseState, useReducer, useEffect, and useLayoutEffect

Managing State and Side Effects in React

React has revolutionized front-end development by introducing hooks that simplify managing state and side effects. For software engineers, business leaders, or students with IT knowledge, mastering these hooks — useState, useReducer, useEffect, and useLayoutEffect — is crucial for building scalable, maintainable, and performant React applications.
INTRODUCTION

Introduction to React State Management and Side Effects

React components are the building blocks of UI, and their ability to manage state effectively is key to a seamless user experience. State refers to data that determines the component’s behavior and rendering. Side effects include operations like data fetching, subscriptions, or manually manipulating the DOM that occur after rendering.

React provides hooks — functions that let you use React state and lifecycle features in functional components. Four foundational hooks are:

Local State with useState

useState is the simplest hook for managing local state in functional components. It returns a state variable and a function to update it. 1

Use Cases
Copy to clipboard
import { useState } from "react";

function App() {
  // state
  const [favorite, setFavorite] = useState("JavaScript");

  return (
    <>
      <h1>My favorite language is {favorite}</h1>
      <h6>Click the button to change favorite</h6>
      <button onClick={() => setFavorite("Python")}>Python</button>
      <button onClick={() => setFavorite("PHP")}>PHP</button>
      <button onClick={() => setFavorite("Java")}>Java</button>
      <button onClick={() => setFavorite("C#")}>C#</button>
    </>
  );
}

export default App;

Complex State Logic Using useReducer

useReducer is preferred when state logic is complex or depends on previous states. It allows you to centralize state updates through a reducer function, similar to Redux but scoped to a component. 2

Use Cases
Copy to clipboard
import { useReducer } from "react";

// initial
const intialState = {
  count: 0,
};

// types
type State = typeof intialState;

type Action = {
  type: "increment" | "decrement";
};

/**
 * This is a reducer function that takes in a state and an action object
 * and returns a new state based on the action type.
 */
function reducer(state: State, action: Action) {
  switch (action.type) {
    case "increment":
      return { count: state.count + 1 };
    case "decrement":
      return { count: state.count - 1 };
    default:
      return state;
  }
}

function App() {
  // states
  const [state, dispatch] = useReducer(reducer, intialState);

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

export default App;

Managing Side Effects with useEffect

Side effects happen outside React’s rendering, such as fetching data, subscriptions, or timers. `useEffect` allows you to perform these asynchronously after the component renders. Avoid pitfalls like missing dependencies or creating infinite loops 3

Use Cases
Basic Syntax
Copy to clipboard
// import { useState } from "react";

useEffect(() => {
  // effect logic here

  return () => {
    // optional cleanup
  };
}, [dependencies]);
Example: Data Fetching
Copy to clipboard
import { useEffect, useState } from "react";

function App() {
  // states
  const [data, setData] = useState<string[]>([]);
  useEffect(() => {
    // In this example, useEffect is used to fetch data from an API.
    // The effect runs once, after the initial render, and fetches data from a hypothetical API that returns an array of strings.
    // The fetched data is stored in the data state variable using the setData function.
    setTimeout(() => {
      const newData = ["a", "b", "c", "d"];
      setData(newData);
    }, 3000);
  }, []);
  return (
    <>
      <p>
        {data?.length > 0
          ? data.map((item: any) => <p>{item}</p>)
          : "loading..."}
      </p>
    </>
  );
}

export default App;

Explore project snapshots or discuss custom solutions.

ASYNC

Synchronous Effects with useLayoutEffect

useLayoutEffect is similar to useEffect but runs synchronously after all DOM mutations but before the browser paints. It’s ideal for measuring or manipulating layout to prevent flickers. 4

Use Cases
Use useLayoutEffect when you must read layout or synchronously re-render before the user sees anything
Copy to clipboard
import { useLayoutEffect, useRef, useState } from "react";

function App() {
  // states
  const ref = useRef<HTMLDivElement>(null);
  const [width, setWidth] = useState(0);

  // useLayoutEffect is used to update the width of the div
  useLayoutEffect(() => {
    setWidth(ref.current?.getBoundingClientRect().width || 0);
  }, [ref]);

  return (
    <>
      <div ref={ref}>Width: {width}px</div>
    </>
  );
}

export default App;

Common Pitfalls

Mastering React hooks for state and side effects empowers you to build robust, efficient, and clean applications whether you are a developer, manager, or entrepreneur.

Comparison

Hook Purpose Use Case Characteristics
useState Declares a state variable Simple, independent state management Easy for primitive or small state. Directly update state variable.
useReducer Declares state with reducer function Complex state logic, multiple related state values Better for complex transitions, ties multiple properties, uses dispatch.
useEffect Handles side effects Data fetching, subscriptions, effects after render Runs after render. Dependency array for controlled execution.
useLayoutEffect Synchronous effect before paint Measure DOM, sync mutations before painting For DOM measurements. Blocks paint until effect finishes, runs earlier.

The best performance improvement is the transition from the nonworking state to the working state.

John Ousterhout A Philosophy of Software Design

Thank You for Spending Your Valuable Time

I truly appreciate you taking the time to read blog. Your valuable time means a lot to me, and I hope you found the content insightful and engaging!
Front
Back
Right
Left
Top
Bottom
FAQ's

Frequently Asked Questions

Use useReducer for complex state with multiple sub-values or when the next state depends on the previous one

This often happens due to missing or incorrect dependencies, or React Strict Mode running effects twice in development, But live version only one time.

No, useLayoutEffect runs synchronously and accesses the DOM, which is not available during server-side rendering.

A cleanup function releases resources or cancels subscriptions to prevent memory leaks when a component unmounts or before the effect re-runs.

Always specify dependency arrays explicitly, and don't update state unnecessarily within the effect.

  1. Available at: https://reactjs.org/docs/hooks-state.html
  2. Available at: https://reactjs.org/docs/hooks-reference.html#usereducer
  3. Available at: https://reactjs.org/docs/hooks-effect.html
  4. Available at: https://reactjs.org/docs/hooks-reference.html#uselayouteffect

Comments are closed