Beginner's Guide to React Hooks: Understanding the Basics

Hugo TavaresHugo Tavares
3 min read

React Hooks, introduced in React 16.8, enable state and lifecycle features in functional components without using classes. This article covers the basics of useState and useEffect with practical examples, including state management, handling side effects, and creating custom hooks for reusable logic.


Introduction 🔌

React Hooks, introduced in React 16.8, have revolutionized how developers build components. They allow you to use state and other React features without writing a class. In this article, we will explore the basics of React Hooks, focusing on useState and useEffect, and provide practical examples to help you get started.


What Are Hooks? 🎣

Hooks are functions that let you “hook into” React state and lifecycle features from function components. They make it possible to organize the logic inside a component into reusable isolated units.


useState: State in Functional Components

The useState hook allows you to add state to your functional components. Here's how it works:

import React, { 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>
  );
}

export default Counter;

In this example, useState(0) initializes the state variable count with a value of 0. The setCount function updates the state.


useEffect: Handling Side Effects

The useEffect hook lets you perform side effects in function components. It’s similar to lifecycle methods like componentDidMount, componentDidUpdate, and componentWillUnmount in class components.

import React, { useState, useEffect } from 'react';

function Timer() {
  const [seconds, setSeconds] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setSeconds(seconds => seconds + 1);
    }, 1000);

    return () => clearInterval(interval); // Cleanup on unmount
  }, []); // Empty array means this effect runs only once after the initial render

  return (
    <div>
      <p>{seconds} seconds have elapsed since mounting.</p>
    </div>
  );
}

export default Timer;

Here, useEffect sets up a timer that increments the seconds state every second. The cleanup function, clearInterval, prevents memory leaks by stopping the timer when the component unmounts.


Combining useState and useEffect 🫱🏻‍🫲🏾

Often, you'll need to use multiple hooks together. For example, fetching data when a component mounts:

import React, { useState, useEffect } from 'react';

function FetchData() {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch('https://api.example.com/data')
      .then(response => response.json())
      .then(data => {
        setData(data);
        setLoading(false);
      });
  }, []); // Empty array ensures this effect runs only once

  if (loading) {
    return <p>Loading...</p>;
  }

  return (
    <div>
      <h1>Fetched Data</h1>
      <pre>{JSON.stringify(data, null, 2)}</pre>
    </div>
  );
}

export default FetchData;

This component fetches data from an API and updates the state with the response. The loading state ensures a loading message is shown until the data is fetched.


Custom Hooks: Reusable Logic 🔄️

You can create your own hooks to reuse stateful logic across components. For example, a custom hook for fetching data:

import { useState, useEffect } from 'react';

function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch(url)
      .then(response => response.json())
      .then(data => {
        setData(data);
        setLoading(false);
      });
  }, [url]); // Re-run effect if URL changes

  return { data, loading };
}

export default useFetch;

You can use this custom hook in any component:

import React from 'react';
import useFetch from './useFetch';

function DataDisplay({ url }) {
  const { data, loading } = useFetch(url);

  if (loading) {
    return <p>Loading...</p>;
  }

  return (
    <div>
      <h1>Data</h1>
      <pre>{JSON.stringify(data, null, 2)}</pre>
    </div>
  );
}

export default DataDisplay;

Conclusion ✅

React Hooks provide a powerful way to use state and other React features in functional components. useState and useEffect are just the beginning—there are many other hooks and patterns you can explore to make your components more modular and maintainable. Keep experimenting and happy coding!

0
Subscribe to my newsletter

Read articles from Hugo Tavares directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Hugo Tavares
Hugo Tavares

Hello World, my name is Hugo. I’m a Christian, husband, and father. I hold a degree in Administration and have experience in the military as an air traffic controller. Additionally, I’m a frontend developer, fascinated by technology, and constantly seeking to learn new things.