Skip to main content

Command Palette

Search for a command to run...

React Hooks for MERN Developers

Updated
11 min readView as Markdown

Understanding useState, useEffect, and Custom Hooks

Target Audience: MERN Developers Prerequisites: React Components, Props, State Goal: Understand how React remembers information, performs side effects, and reuses logic using Hooks.


How Does React Remember Information Between Renders?

Imagine a simple React component.

function Counter() {
    let count = 0;

    return (
        <>
            <h1>{count}</h1>

            <button onClick={() => count++}>
                Increment
            </button>
        </>
    );
}

Looks correct.

Click the button.

Nothing happens.

Why?

Because every time React renders the component, the function executes again.

Render 1

count = 0

↓

Click Button

↓

count = 1

↓

React Renders Again

↓

count = 0

The variable is recreated.

React doesn't remember ordinary JavaScript variables.

This raises an important question.

How does React remember information between renders?

The answer is Hooks.


Why Were React Hooks Introduced?

Before Hooks, React developers used Class Components.

class Counter extends React.Component {
    state = {
        count: 0
    };
}

Large applications became difficult to manage because:

  • Logic was spread across lifecycle methods.

  • Reusing stateful logic was difficult.

  • Components became very large.

  • this keyword caused confusion.

  • Lifecycle methods were hard to understand.

Hooks solved these problems.


Benefits of Hooks

Hooks made React:

  • Simpler

  • More readable

  • Easier to maintain

  • Easier to test

  • Better at reusing logic

  • Less dependent on classes

Today, almost all modern React applications use Function Components + Hooks.


What Are Hooks?

Hooks are special React functions that allow function components to use:

  • State

  • Side Effects

  • Context

  • Reusable Logic

Examples

useState

useEffect

useContext

useMemo

useCallback

Every Hook begins with use.


Understanding useState

What is useState?

useState allows React components to store information between renders.

const [count, setCount] = useState(0);

Think of it like this:

React

↓

Stores Value

↓

Returns Current State

↓

Returns Function to Update It

Breaking Down useState

const [count, setCount] = useState(0);

Here:

count

Current value.

setCount()

Updates value.

0

Initial value.


Counter Example

function Counter() {
    const [count, setCount] = useState(0);

    return (
        <>
            <h1>{count}</h1>

            <button
                onClick={() => setCount(count + 1)}
            >
                Increment
            </button>
        </>
    );
}

Flow

Button Click

↓

setCount()

↓

State Changes

↓

React Re-renders

↓

Updated UI

Why Can't We Change State Directly?

Wrong

count = count + 1;

React won't know anything changed.

Correct

setCount(count + 1);

The setter tells React

"State has changed. Please render again."


Multiple State Variables

A component can have many pieces of state.

const [name, setName] = useState("");

const [email, setEmail] = useState("");

const [age, setAge] = useState(21);

Each state variable is independent.


State-Driven UI

React follows one simple rule:

State

↓

UI

If state changes,

UI changes automatically.

Example

Theme = Light

↓

Button Click

↓

Theme = Dark

↓

Entire UI Updates

Common State Patterns

Examples of state:

  • Counter

  • Theme

  • Search Input

  • Form Fields

  • Shopping Cart

  • Modal Visibility

  • Selected Tab

  • Loading Spinner

Not everything should be state.

Only values that affect rendering belong in state.


Understanding React Re-renders

Many beginners think:

"React refreshes the whole page."

It doesn't.

React re-renders components.


What is a Re-render?

Whenever state changes,

React runs the component function again.

State Changes

↓

Component Function Runs Again

↓

New JSX

↓

Compare with Previous UI

↓

Update DOM

What Triggers a Re-render?

1. State Updates

setCount(count + 1);

2. Props Changes

Parent passes different props.

Child renders again.


3. Context Changes

Context updates.

Consumers re-render.


React Rendering Flow

State

↓

Render

↓

Virtual DOM

↓

Diffing

↓

Real DOM Updates

React updates only the parts of the page that changed.


Common Misconceptions

Wrong

Every render is bad.

Correct

Rendering is normal.

Unnecessary rendering is the problem.

Avoid Unnecessary State

Bad

const [fullName, setFullName] =
useState(first + last);

Better

const fullName =
first + last;

Derived values usually don't need state.


Understanding useEffect

Why Does useEffect Exist?

React components should mainly describe UI.

Sometimes we need to interact with the outside world.

Examples

  • API Requests

  • Timers

  • Browser Events

  • Local Storage

  • WebSockets

These are called Side Effects.


What is a Side Effect?

Anything that affects something outside the component.

Examples

Fetching Data

Saving Data

Console Logging

Changing Document Title

Adding Event Listeners

Starting Timers

What Does useEffect Do?

It lets React synchronize your component with external systems.

useEffect(() => {
    console.log("Component rendered");
});

Data Fetching Example

useEffect(() => {
    fetch("/api/users")
        .then(...)
}, []);

Flow

Component Appears

↓

useEffect Runs

↓

API Request

↓

State Updates

↓

UI Updates

Event Listener Example

useEffect(() => {

    window.addEventListener(...);

}, []);

Timer Example

useEffect(() => {

    const id = setInterval(...);

}, []);

Cleanup Functions

Some side effects must be cleaned up.

Example

useEffect(() => {

    const id = setInterval(...);

    return () => {
        clearInterval(id);
    };

}, []);

Cleanup prevents:

  • Memory leaks

  • Duplicate timers

  • Duplicate listeners


Dependency Arrays Explained

One of the most misunderstood React topics.

Syntax

useEffect(() => {

}, []);

The second argument is the dependency array.


Empty Dependency Array

useEffect(() => {

}, []);

Runs

Once

↓

After First Render

Perfect for

  • API Calls

  • Initial Setup


Dependencies Included

useEffect(() => {

}, [user]);

Runs

First Render

↓

Whenever user changes

No Dependency Array

useEffect(() => {

});

Runs

Every Render

Usually not what you want.


Common Dependency Mistakes

Missing Dependencies

React warns

Missing Dependency

because your effect may use stale values.


Infinite Loops

useEffect(() => {

    setCount(count + 1);

}, [count]);

Flow

Effect

↓

setCount()

↓

Render

↓

Effect

↓

setCount()

↓

Forever

Always understand why an effect runs before updating state inside it.


Common useEffect Patterns

Fetching Data

Render

↓

Fetch API

↓

Update State

↓

Display Data

Browser Events

Mount

↓

Add Event Listener

↓

Unmount

↓

Remove Listener

Synchronizing External Systems

Examples

  • Local Storage

  • Cookies

  • WebSocket Connections

  • Browser Title

  • Analytics

useEffect keeps React synchronized with systems outside React.


Lifecycle Thinking

Older React

componentDidMount

componentDidUpdate

componentWillUnmount

Modern React

Think

"Synchronize with external systems."

Not

"Run after mount."

This mindset leads to cleaner effects.


Custom Hooks

What Are Custom Hooks?

Custom Hooks are JavaScript functions that use other Hooks.

Example

function useCounter() {

}

Notice the name starts with

use

Why Do Custom Hooks Exist?

Imagine five components all fetch user data.

Without custom hooks

Component A

↓

Fetch Logic

Component B

↓

Fetch Logic

Component C

↓

Fetch Logic

Lots of duplication.


With a custom hook

useUser()

↓

Component A

Component B

Component C

Shared logic.


Reusing Stateful Logic

Custom Hooks allow multiple components to share logic while maintaining independent state.

Each component gets its own instance.


Separating Concerns

Bad

Dashboard.jsx

↓

500 Lines

↓

Everything Together

Better

Dashboard

↓

useAuth()

↓

useFetch()

↓

useTheme()

↓

Cleaner Component

Common Custom Hooks

Authentication

useAuth()

Data Fetching

useUsers()

useProducts()

usePosts()

Forms

useForm()

Theme

useTheme()

Window Size

useWindowSize()

Device Information

useOnlineStatus()

useDarkMode()

useLocalStorage()

When Should You Create a Custom Hook?

Create one when:

  • Logic is repeated.

  • State management is shared.

  • Side effects are duplicated.

  • Components become too large.

Don't create custom hooks for one-time logic.


Rules of Hooks

React Hooks follow strict rules.

Rule 1

Only call Hooks at the top level.

Wrong

if (loggedIn) {
    useEffect(...);
}

Correct

useEffect(...);

Rule 2

Only call Hooks inside:

  • React Components

  • Custom Hooks

Never inside:

  • Loops

  • Conditions

  • Nested Functions


Why These Rules Exist

React identifies Hooks by the order in which they are called.

Example

Render 1

useState

useEffect

useState

Render 2 must follow the same order.

Changing the order confuses React.


Organizing Hooks

A common structure

Component

↓

Hooks

↓

Derived Values

↓

Functions

↓

JSX

Keeps components readable.


Common Hook Mistakes

  • Forgetting dependencies.

  • Updating state unnecessarily.

  • Using useEffect for calculations.

  • Writing huge useEffect blocks.

  • Creating custom hooks too early.

  • Calling Hooks conditionally.


Thinking in Hooks

Instead of asking

"Where do I write this code?"

Ask

"What responsibility does this code have?"


If it changes UI

State


If it synchronizes with the outside world

useEffect


If it is reused

Custom Hook


React Hooks Mental Model

User Action

↓

setState()

↓

React Re-renders

↓

New JSX

↓

DOM Updates

↓

useEffect Synchronizes

Everything revolves around:

  • State

  • Rendering

  • Synchronization


Modern React Architecture

App

├── Components

├── Local State

├── Custom Hooks

├── Context

└── Effects

Hooks help keep each concern separate and reusable.


Interview Questions

Why were Hooks introduced?

To simplify component development, replace many class component patterns, and enable reusable stateful logic in function components.


What does useState do?

It stores state between renders and provides a setter function that tells React to re-render when the state changes.


What triggers a re-render?

  • State updates

  • Prop changes

  • Context updates


What is useEffect?

A Hook used to synchronize React components with external systems such as APIs, timers, browser events, and storage.


What is a Side Effect?

Any operation that interacts with something outside React's rendering process.

Examples include API calls, timers, subscriptions, and browser APIs.


What does an empty dependency array mean?

The effect runs once after the component's initial render.


What happens without a dependency array?

The effect runs after every render.


Why do infinite loops happen in useEffect?

Because the effect updates state, which triggers another render, causing the effect to run again repeatedly.


What are Custom Hooks?

Reusable JavaScript functions that combine Hooks and encapsulate stateful logic for use across multiple components.


Why must Hooks always be called at the top level?

Because React relies on the order of Hook calls remaining the same on every render.


Key Takeaways

  • Hooks allow function components to manage state, side effects, and reusable logic.

  • useState gives components memory across renders and drives UI updates.

  • React re-renders components when state, props, or context change.

  • useEffect is designed for synchronizing components with external systems—not simply replacing lifecycle methods.

  • Dependency arrays control when effects run and help avoid unnecessary work or infinite loops.

  • Cleanup functions prevent memory leaks by removing subscriptions, timers, and event listeners.

  • Custom Hooks encourage code reuse and separation of concerns by extracting shared stateful logic.

  • Following the Rules of Hooks ensures predictable execution and prevents subtle bugs.

  • Thinking in Hooks means separating state, rendering, and synchronization into clear responsibilities.

  • Mastering these fundamentals prepares you for advanced React concepts such as Context, reducers, routing, data fetching libraries, and state management solutions.