React Hooks Explained: useState and useEffect with Simple Examples
Originally published on CodingCush. React Hooks are special functions that let function components remember values and do extra work, such as fetching data or updating the page title. Before Hooks, you often needed a cl
Originally published on CodingCush.
React Hooks are special functions that let function components remember values and do extra work, such as fetching data or updating the page title. Before Hooks, you often needed a class component for these jobs. Since React 16.8, two Hooks cover most everyday needs: useState gives a component memory, and useEffect lets it react after rendering. Learn these two well, and most beginner React code suddenly starts to make sense.
What Are React Hooks?
A Hook is simply a function whose name starts with the word use. React provides built in Hooks, and the two you will meet first are useState and useEffect. You import them from React, call them inside a function component, and React connects them to that component behind the scenes.
Think of a function component as a small machine that draws part of your screen. On its own, it forgets everything each time it runs. useState gives it a notebook, so it can remember a number, a name or whether a menu is open. useEffect gives it an assistant who works after the screen has been drawn, such as loading data from a server.
If components still feel new, start with our guide to React components, props and state explained, then come back here. The official React Learn guide on react.dev is also a friendly place to practise each idea step by step.
The Two Rules of Hooks
Hooks are easy to use, but they follow two strict rules. React relies on them to match each Hook call with the right piece of memory, so they are not optional advice.
Rule 1: Only call Hooks at the top level. Do not call them inside loops, conditions or nested functions. Always call them in the same order on every render, at the top of your component.
Rule 2: Only call Hooks in React functions. That means inside function components, or inside your own custom Hooks. Do not call them in regular JavaScript functions that have nothing to do with React.
Follow these rules and React stays calm and organised. Break them, and React can mix up its notebook pages, which leads to confusing bugs.
useState: Giving a Component Memory
useState is the Hook you use when a value needs to be remembered and the screen needs to update when that value changes. You call it with a starting value, and it returns two things in an array: the current value, and a function to update it.
Here is a simple counter. Every click calls setCount, React stores the new number, and the component renders again with the updated value.
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
Notice the pattern. count holds the value, setCount changes it, and 0 is the starting value. You never change count directly. You always ask React to change it through setCount, so React knows it must draw the screen again.
useState works just as well with text. This second example stores what a visitor types into an input box, which is the pattern behind almost every form you will build.
import { useState } from "react";
function NameForm() {
const [name, setName] = useState("");
return (
<div>
<input
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Type your name"
/>
<p>Hello, {name || "friend"}!</p>
</div>
);
}
As the visitor types, each keystroke updates name, and the greeting below updates at the same time. If the syntax with curly braces looks new, our explainer on what JSX is in React will help. The official useState reference also covers updating objects and arrays safely.
The React Learn page on react.dev, where the official guides teach components and state step by step.
useEffect: Doing Work After Rendering
useEffect is for side effects. A side effect is any work that reaches outside the simple job of drawing the screen, such as changing the document title, starting a timer, or fetching data from an API. You give useEffect a function, and React runs that function after rendering.
This example keeps the browser tab title in step with the counter. Every time count changes, the effect runs and writes a new title.
import { useState, useEffect } from "react";
function TitleCounter() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `Clicked ${count} times`;
}, [count]);
return (
<button onClick={() => setCount(count + 1)}>
Clicked {count} times
</button>
);
}
The second argument, [count], is called the dependency array, and it controls when the effect runs. If you leave the array out, the effect runs after every render. If you pass an empty array, [], it runs only once, after the first render. If you pass values like [count], it runs after the first render and again whenever one of those values changes.
That empty array pattern is exactly what you use when fetching data on page load. The request should happen once, not again and again on every render.
import { useState, useEffect } from "react";
function UserList() {
const [users, setUsers] = useState([]);
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/users")
.then((response) => response.json())
.then((data) => setUsers(data));
}, []);
return (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
Here useState stores the list, useEffect loads it once, and setUsers saves the result so React can draw the names. The two Hooks work as a team in real apps far more often than they work alone.
useState vs useEffect at a Glance
The simplest way to keep the two Hooks apart is to ask one question: am I remembering a value, or am I doing work after the screen changes? Remembering belongs to useState. Doing work belongs to useEffect.
| Point | useState | useEffect |
|---|---|---|
| Job | Stores a value and updates the screen when it changes | Runs side effects after rendering |
| When it runs | During rendering, and when you call its setter function | After rendering, based on the dependency array |
| Example use | A counter, a form input, an open or closed menu | Fetching data, updating the document title, timers |
Keep this table nearby while you practise. After a few small projects, choosing between them becomes automatic.
Common Beginner Mistakes
Calling Hooks inside if statements or loops. If a Hook only runs on some renders, the order of Hook calls changes, and React loses track of its memory. Move the Hook to the top level and put the condition inside the component logic instead.
Forgetting the dependency array. An effect that fetches data without [] runs after every render. If that effect also updates state, the component renders again, the effect runs again, and you have built a very enthusiastic infinite loop. Add the array and list every value from the component that the effect uses.
Updating state during rendering. Calling a setter directly in the body of a component, instead of inside an event handler or an effect, makes React render, update, render and update forever. Always update state in response to something, such as a click, a keystroke or a finished fetch.
Changing state directly. Writing count = count + 1 does nothing useful, because React does not notice plain variable changes. Always use the setter function that useState gave you.
Frequently Asked Questions
What is the difference between useState and useEffect?
useState stores a value that the component needs to remember, and updates the screen when that value changes. useEffect runs work after rendering, such as fetching data or changing the page title.
Why does my useEffect run twice or keep looping?
It usually means the dependency array is missing or wrong. Without an array, the effect runs after every render. Add [] to run it once, or list the exact values it depends on.
Can I use more than one useState in a component?
Yes, and you should. Use one useState call per value, such as one for a name, one for an email and one for a loading flag. Separate values are easier to read and update than one giant object.
Do Hooks work in class components?
No. Hooks only work in function components and in custom Hooks. Class components use their older state and lifecycle methods instead, which is one reason new React code prefers functions.
Conclusion
Hooks sound mysterious at first, but the idea is refreshingly small. useState remembers values and redraws the screen when they change. useEffect does work after rendering, and its dependency array decides how often. Respect the two rules, avoid the mistakes above, and build two or three tiny projects this week. A counter, a small form and one data fetching list will teach your fingers more than a weekend of reading ever could.
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.