DEV Community

Cover image for React Hooks for Beginners: The Guide I Wish I Had

React Hooks for Beginners: The Guide I Wish I Had

If you’re getting into React and everyone keeps yelling “Use hooks! Use hooks!” but you don't understand what hooks are or even how to use them, don’t worry, you’re not alone. When I first heard the word “hooks”, I genuinely thought React wanted me to go fishing.

Spoiler alert: it didn’t. 😭🎣

Hooks are special functions that let you “hook into” React features, things like state, lifecycle events, and reusable logic, without writing classes. They make your components smarter, more readable, and honestly… they save you from a lot of stress.

In this article, I’m breaking everything down in the easiest way possible. No jargon. No confusion. Real examples. By the end, you’ll understand exactly what hooks are, why they exist, and how to use the most common ones confidently.

Let’s dive in! 🚀

What Exactly Are React Hooks?

Imagine your component is a tiny human brain.

React Hooks give the brain the ability to

  • store memories,
  • send reactions,
  • create habits,
  • and have mini superpowers.

Do you want your component to remember something? → useState

Do you want it to react when something changes? → useEffect

Do you want to avoid repeating the same logic everywhere? → custom hooks

Do you want to grab something from multiple components? → useContext

Basically, hooks allow functional components to do everything class components could, but in a cleaner, more modern, and less headache-inducing way.

Why Do Hooks Even Exist?

Before hooks, React had classes. And classes were…
Let’s just say they were the “senior developer who refuses to retire.”

React Hooks came to:

  • Reduce boilerplate
  • Make components readable
  • Share logic easily between different components
  • Make React code feel natural and modern

So yeah, React Hooks === fewer tears, fewer bugs, and cleaner functionality overall.

Let’s Break Down Some of the Most Important Hooks

As of React 19 (version 19), there are 19 built-in React hooks, including state management hooks, side effect hooks, reference hooks, performance optimization hooks, scheduling hooks, etc.

Let's discuss some of the most commonly used built-in hooks:

1. useState - Your Component’s Memory

This hook lets your component remember and track things easily.

Think of it like this:
If you want to store your money and track expenses so you know what’s left at every moment, you keep the money in a bank.

Well, in React, that bank is the useState hook.

And this bank gives you back two things:

  • Your current balance → the state
  • A way to update your balance → the set function

That’s literally it.

So anytime you want to store a value and update it later, useState is your guy.

Example:

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

  return (
    <button onClick={() => setCount(count + 1)}>
      You clicked {count} times
    </button>
  );
}

Enter fullscreen mode Exit fullscreen mode

From our example, the useState hook accepts an initial value/state, which is 0, and it returns two values. The current state, which is count, and the function used to update the state, which is setCount.

To understand useState better and have some practices as well, you can check out these resources:

2. useEffect - "Do something when something else happens."

Let’s say your component needs to run some code after something changes, like fetching data, updating the page title, or reacting to user actions (event handlers).

useEffect is basically the “when X happens, do Y” hook.

Think of it like a smart assistant:

“Oh, the page just loaded? Want me to fetch something?”

“Did the user update the count? Want me to run this?”

“Did the component disappear? Want me to clean things up?”

Example:

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

Enter fullscreen mode Exit fullscreen mode

This runs only when the count changes.

Some use cases for the useEffect hook include:

  • Fetch data from an API
  • Listen for events
  • Update the document title
  • Sync state with localStorage
  • Run cleanup when components unmount, etc.

Basically… whenever you say “React, please do this when that changes,” you reach for the useEffect hook.

To understand useEffect better and have some practices as well, you can check out these resources:

3. useRef - A Secret Storage Box That Doesn’t Trigger Re-renders

useRef is like a tiny storage room where you can keep things… and React won’t bother re-rendering the component because of it.

A re-render is when React runs your component function again to figure out what the UI should look like. Hooks like useState normally trigger re-renders because the UI needs to update whenever the state changes.

But sometimes you want to store something without re-rendering your component, like when it's not UI-related.
That’s where useRef comes in. It lets you store values that can change… quietly… without React re-running your component.

It’s great for:

  • Accessing DOM elements
  • Storing previous values
  • Keeping intervals/timeouts
  • Tracking something that changes but shouldn’t re-render (that's update) the UI

Example:

const inputRef = useRef();

function focusInput() {
  inputRef.current.focus();
}

return (
   <div>
     <button onClick={() => focusInput()}>
       Focus input
     </button>

     <input ref={inputRef} />
   </div>
  );

Enter fullscreen mode Exit fullscreen mode

So when you click the button to focus the input, useRef helps you grab the actual DOM element.

Important:
useRef only returns one thing, an object with a single property called current.
Whatever you store inside current will stay there between renders without causing a re-render.

To understand useRef better and have some practices as well, you can check out these resources:

4. useContext - Sharing Values Without Passing Props Through 500 Components

Sometimes your app needs to share data between multiple components (like theme, user info, and language settings). Passing props through every child component becomes messy FAST (also known as Prop Drilling).

That’s where useContext comes in.

useContext is a way to manage state/data globally in your application. It can be used together with the useState hook to share state between various components.

Example:

const ThemeContext = createContext();

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Child />
    </ThemeContext.Provider>
  );
}

function Child() {
  const theme = useContext(ThemeContext);
  return <div>Theme is {theme}</div>;
}

Enter fullscreen mode Exit fullscreen mode

From the example above, we created a context called ThemeContext and wrapped it around the child component. That way, we can get the value stored in the context into our child component without needing to pass it as a prop.

No prop drilling. No stress.

To understand useContext better and have some practices as well, you can check out these resources:

5. useMemo - Prevents React from Recalculating Too Much

Think of useMemo like this:

Imagine you’re doing a very hard math problem. Like… “calculate the number of grains of sand on the beach”.

It takes time. It takes brain power. It takes stress.

Now imagine that every time someone asks you a new question, you have to solve that sand problem AGAIN from scratch.
You would cry. React would cry. Everyone would cry. 😭

That’s what happens when you put expensive calculations directly inside your component.
Every time the component re-renders (even for small reasons), the calculation runs again.

useMemo is React saying:

“Let's just remember the result so we don’t have to re-calculate it every single time.”

React will only redo the calculation when the dependency changes.

Example:
Let’s say you have a function that calculates the total score from a huge list of scores.

function App({ scores }) {
  const total = useMemo(() => {
    console.log("Calculating total...");
    return scores.reduce((acc, s) => acc + s, 0);
  }, [scores]);

  return <h1>Total Score: {total}</h1>;
}

Enter fullscreen mode Exit fullscreen mode

If the scores array doesn’t change, React will not recalculate the total.
It will reuse the previously stored (memoized) result.

Use useMemo when:

  • You are doing a heavy or expensive calculation
  • You are dealing with large lists, filters, or sorting
  • You want to avoid laggy UI
  • You only want React to re-calculate when a specific value actually changes

To understand useMemo better and have some practices as well, you can check out these resources:

6. useCallback - “Please stop creating this function again and again.”

This one can be a little bit confusing, so here’s the easiest way to think about it:

React re-renders components all the time. And on every render, React recreates every function inside the component.

Most of the time, this is fine.
But sometimes… it causes problems. Especially when:

  • You pass a function to a child component
  • That child uses React.memo()
  • OR the function triggers unnecessary re-renders

So useCallback steps in like:

“Hey, React, chill. Use the OLD version of this function unless something important changes.”

Example:

const handleClick = useCallback(() => {
  console.log("clicked");
}, []);

Enter fullscreen mode Exit fullscreen mode

React will reuse the same function on every render because the dependency array is empty. But if there was a value in the dependency array, then React will only re-create or recalculate this function when that value changes.

Another Example:


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

  const increment = useCallback(() => {
    setCount(c => c + 1);
  }, []);

  return <Child onIncrement={increment} />;
};


Enter fullscreen mode Exit fullscreen mode

If you didn’t use useCallback, the Child would re-render every time the Parent re-renders, even if nothing changed.

With useCallback, the function reference stays the same, so the child doesn’t freak out.

Use useCallback when:

  • You pass functions to child components
  • You're using React.memo()
  • You want to prevent unnecessary re-renders
  • The child component depends on the function identity

You don’t need useCallback for everything.

If a function is tiny and you’re not passing it around, don't bother.
It’s more of a performance optimization tool than an everyday tool.

To understand useCallback better and have some practices as well, you can check out these resources:

Wrapping Up

And just like that, React Hooks don’t feel like dark magic anymore.

If hooks used to confuse you, I hope this guide made them feel less intimidating and a lot more human. They’re not scary, they’re just tools. And now you know exactly what the most common ones do, why they exist, and when to reach for them.

Hooks aren’t something you “master in one day,” but now you’ve got the foundation, the mindset, and the confidence to start using them without panicking.

Keep practicing, keep experimenting, and trust me, it only gets easier from here.

Top comments (0)