3/8/2026 | react | javascript | frontend | web development | react hooks

React's Two Most Important Hooks: useState vs useEffect

photo-1633356122544-f134324a6cee.jpg

React's Two Most Important Hooks: useState vs useEffect

If React components were living creatures, they would need two things to function:

  • Memory 🧠
  • The ability to interact with the outside world 🌍

In React, these powers come from two hooks:

useState
useEffect

Mastering them is the moment React suddenly clicks.

This article will show:

  • what they do
  • when to use them
  • how they work together
  • mistakes beginners make

1️. useState β€” The Memory of Your Component

Every React component needs memory.

For example:

  • a counter needs to remember its value
  • a form needs to remember what the user typed
  • a modal needs to remember whether it is open

That memory lives in state.

React gives us state using the useState hook.

Basic Example

import { useState } from "react";

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

  const increment = () => {
    setCount(prev => prev + 1);
  };

  return (
    <button onClick={increment}>
      Count: {count}
    </button>
  );
}

What’s happening here?

PartMeaning
countThe current value
setCountFunction to update the value
useState(0)Initial state

Whenever setCount runs, React:

  1. updates the state
  2. re-renders the component
  3. updates the UI

Where useState is Used in Real Apps

You will use it everywhere.

Form Inputs

const [username, setUsername] = useState("");

Toggle UI Elements

const [isOpen, setIsOpen] = useState(false);

API Data Storage

const [posts, setPosts] = useState([]);

Think of useState as:

The variable that React remembers between renders

2️. useEffect β€” React's Portal to the Outside World

React components are supposed to be pure functions.

But real apps need to do things like:

  • fetch data
  • start timers
  • subscribe to events
  • update the document title

These are called side effects.

And React handles them using:

useEffect

A Simple Example

import { useEffect } from "react";

useEffect(() => {
  console.log("Component mounted!");
}, []);

This runs once when the component loads.

Why?

Because of the dependency array.


The Dependency Array (The Secret Sauce)

The second argument controls when the effect runs.

Run Once

useEffect(() => {
  fetchPosts();
}, []);

Runs when the component first mounts.

Common uses:

  • API calls
  • loading data
  • initializing things

Run When Something Changes

useEffect(() => {
  console.log("Count changed");
}, [count]);

Runs whenever count updates.


Run Every Render

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

This runs after every render.

⚠️ Usually you do not want this.


A Real Example: Fetching Data

const [posts, setPosts] = useState([]);

useEffect(() => {
  fetch("/api/posts")
    .then(res => res.json())
    .then(data => setPosts(data));
}, []);

Flow of events:

Component mounts
      ↓
useEffect runs
      ↓
API request happens
      ↓
State updates
      ↓
UI re-renders with data

Cleanup Functions (A Hidden Superpower)

Sometimes effects create ongoing processes, like:

  • timers
  • event listeners
  • subscriptions

These must be cleaned up.

Example:

useEffect(() => {
  const interval = setInterval(() => {
    console.log("Tick");
  }, 1000);

  return () => clearInterval(interval);
}, []);

When the component unmounts, React runs the cleanup function.

Without cleanup, your app can leak memory.


When to Use Each Hook

SituationHookReason
Form inputuseStateTrack what user typed
Toggle menuuseStateUI state
Fetch API datauseEffectSide effect
TimeruseEffectUses interval
Search featureBothState stores query, effect triggers fetch

When They Work Together (The Real Magic)

Most real features use both hooks together.

Example: Auto-saving a blog editor

const [content, setContent] = useState("");

useEffect(() => {
  const interval = setInterval(() => {
    saveToDatabase(content);
  }, 30000);

  return () => clearInterval(interval);
}, [content]);

What happens here?

User types
   ↓
State updates
   ↓
Effect notices change
   ↓
Auto-save triggers

Common Beginner Mistakes

Infinite Loops

useEffect(() => {
  setCount(count + 1);
}, [count]);

This causes React to re-render forever.


Missing Dependencies

Bad:

useEffect(() => {
  fetchUser(userId);
}, []);

Correct:

useEffect(() => {
  fetchUser(userId);
}, [userId]);

Overusing useEffect

Not everything needs an effect.

Rule:

If it can run during render, it should not be inside useEffect.


The Mental Model That Makes React Click

Think of it like this:

useState  = memory
useEffect = reactions

Or visually:

State changes
      ↓
React renders UI
      ↓
Effects run afterwards

Quick Comparison

FeatureuseStateuseEffect
PurposeStore dataRun side effects
Causes renderYesNo
Runs whenState updatesAfter render
Examplesforms, togglesAPI calls, timers

Final Thoughts

Learning React often feels confusing at first.

But once you understand these two ideas:

State stores data
Effects react to changes

Everything starts to make sense.

Every React application β€” from tiny widgets to massive dashboards β€” is built on top of these two hooks working together.

Master them, and you're no longer just using React.

You're thinking in React.