DEV Community

Cover image for A Complete Guide to All React Hooks for Beginners
Pedro Henrique Machado
Pedro Henrique Machado

Posted on

A Complete Guide to All React Hooks for Beginners

React hooks revolutionized the way we build components by allowing us to use state and other features in functional components. In this tutorial, we’ll dive deep into all the current React hooks, walking you through practical examples. By the end of this article, you'll have a solid understanding of how each hook works and how you can use them to build better React applications.

If you want to see this guide in video form, check out this video:

Introduction

React hooks are functions that let you "hook into" React's state and lifecycle features from function components. Before hooks, React only allowed these features in class components. Since the introduction of hooks, you can now write fully functional components with powerful capabilities, leading to cleaner and more readable code.

In this article, we’ll cover the most important hooks in React, from the basic useState to the advanced useSyncExternalStore. Each hook will be explained with a hands-on tutorial.

Project Setup

Let’s begin by setting up a simple React project using Create React App.

  1. First, install Create Your React App if you don't have it:

    npx create-vite
    
  2. Install any dependencies you may need (if you are planning to use additional libraries).

  3. Open the project in your code editor, and start editing App.js. We will demonstrate each hook here with live examples.

useState Hook Tutorial

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); // Declare state

  return (
    <div>
      <h1>{count}</h1>
      <button onClick={() => setCount(count + 1)}>Increase</button>
      <button onClick={() => setCount(count - 1)}>Decrease</button>
    </div>
  );
}

export default Counter;
Enter fullscreen mode Exit fullscreen mode

Key Points:

  • useState accepts the initial state as an argument and returns an array with the state variable and the function to update it.
  • The state persists across re-renders of the component.

useEffect Hook Tutorial

The useEffect hook allows you to perform side effects in your components, such as data fetching, subscriptions, or manually changing the DOM.

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

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

  useEffect(() => {
    fetch('https://api.example.com/data')
      .then(response => response.json())
      .then(data => setData(data));
  }, []); // Empty dependency array to run only once

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

export default FetchData;
Enter fullscreen mode Exit fullscreen mode

Key Points:

  • useEffect is invoked after every render unless you provide a dependency array (like []), which makes it run only once when the component mounts.
  • This hook is ideal for operations that don't directly affect the UI, such as data fetching.

useContext Hook Tutorial

The useContext hook allows you to subscribe to React context and access its value in your components.

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

// Create context
const ThemeContext = React.createContext('light');

function ThemedComponent() {
  const theme = useContext(ThemeContext); // Access context value

  return <div>The current theme is {theme}</div>;
}

function App() {
  const [theme, setTheme] = useState('light');

  return (
    <ThemeContext.Provider value={theme}>
      <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
        Toggle Theme
      </button>
      <ThemedComponent />
    </ThemeContext.Provider>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Key Points:

  • useContext allows functional components to consume context directly without needing a consumer component.
  • It simplifies state sharing across components without prop drilling.

useReducer Hook Tutorial

The useReducer hook is an alternative to useState for managing more complex state logic, especially when the state depends on previous state.

import React, { useReducer } from 'react';

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      return state;
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, { count: 0 });

  return (
    <div>
      <h1>{state.count}</h1>
      <button onClick={() => dispatch({ type: 'increment' })}>Increase</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>Decrease</button>
    </div>
  );
}

export default Counter;
Enter fullscreen mode Exit fullscreen mode

Key Points:

  • useReducer is often used when the state is an object or array and requires complex logic to update.
  • The reducer function is responsible for returning the new state based on the action.

useRef Hook Tutorial

The useRef hook provides a way to reference a DOM element or store a mutable value that doesn't cause re-rendering when updated.

import React, { useRef } from 'react';

function FocusInput() {
  const inputRef = useRef(null);

  const handleFocus = () => {
    inputRef.current.focus();
  };

  return (
    <div>
      <input ref={inputRef} type="text" />
      <button onClick={handleFocus}>Focus Input</button>
    </div>
  );
}

export default FocusInput;
Enter fullscreen mode Exit fullscreen mode

Key Points:

  • useRef is used to access the DOM directly or keep a mutable reference across renders.
  • It does not trigger a re-render when the value changes.

useImperativeHandle Hook Tutorial

useImperativeHandle is used with forwardRef to customize the instance value exposed to parent components when using ref.

import React, { useImperativeHandle, useRef, forwardRef } from 'react';

const FancyInput = forwardRef((props, ref) => {
  const inputRef = useRef();

  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    },
  }));

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

function App() {
  const inputRef = useRef();

  return (
    <div>
      <FancyInput ref={inputRef} />
      <button onClick={() => inputRef.current.focus()}>Focus Input</button>
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Key Points:

  • useImperativeHandle allows you to modify the instance value exposed to the parent through ref.
  • This is useful when you need to expose only specific methods or properties from a child component.

useLayoutEffect Hook Tutorial

useLayoutEffect is similar to useEffect, but it fires synchronously after all DOM mutations. It is useful for reading and modifying the DOM before the browser repaints.

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

function LayoutEffectDemo() {
  const [width, setWidth] = useState(0);

  useLayoutEffect(() => {
    setWidth(window.innerWidth); // Measure DOM before render
  }, []);

  return <div>Window width: {width}</div>;
}

export default LayoutEffectDemo;
Enter fullscreen mode Exit fullscreen mode

Key Points:

  • useLayoutEffect runs synchronously after all DOM mutations, making it ideal for cases where you need to measure or mutate the DOM before it is painted.

useInsertionEffect Hook Tutorial

useInsertionEffect runs before all DOM mutations, useful for injecting styles or performing DOM manipulations.

import React, { useInsertionEffect } from 'react';

function InsertionEffectDemo() {
  useInsertionEffect(() => {
    // Custom DOM manipulation or style injection
    document.body.style.backgroundColor = 'lightblue';
  }, []);

  return <div>Check the body background color!</div>;
}

export default InsertionEffectDemo;
Enter fullscreen mode Exit fullscreen mode

Key Points:

  • useInsertionEffect is for performing operations that need to happen before DOM mutations, like injecting styles.

useId Hook Tutorial

useId provides a unique identifier that is stable across server and client renders.

import React, { useId } from 'react';

function InputWithId() {
  const id = useId();

  return (
    <div>
      <label htmlFor={id}>Input Label</label>
      <input id={id} />
    </div>
  );
}

export default InputWithId;
Enter fullscreen mode Exit fullscreen mode

Key Points:

  • useId is useful for generating unique IDs, ensuring consistency in both server-side rendering (SSR) and client-side rendering (CSR).

useTransition Hook Tutorial

The useTransition hook allows you to manage slow transitions in UI without blocking interaction.

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

function TransitionDemo() {
  const [isPending, startTransition] = useTransition();
  const [value, setValue] = useState("");

  return (
    <div>
      <input
        type="text"
        value={value}
        onChange={(e) => startTransition(() => setValue(e.target.value))}
      />
      {isPending && <div>Loading...</div>}
    </div>
  );
}

export default TransitionDemo;
Enter fullscreen mode Exit fullscreen mode

Key Points:

  • useTransition is great for handling background tasks or slow updates without blocking the user interface.

useDeferredValue Hook Tutorial

The useDeferredValue hook allows you to delay re-rendering non-urgent updates.

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

function DeferredValueDemo() {
  const [value, setValue] = useState("");
  const deferredValue = useDeferredValue(value);

  return (
    <div>
      <input
        type="text"
        value={value}
        onChange={(e) => setValue(e.target.value)}
      />
      <div>{deferredValue}</div>
    </div>
  );
}

export default DeferredValueDemo;
Enter fullscreen mode Exit fullscreen mode

Key Points:

  • useDeferredValue defers rendering a non-urgent value to improve performance, allowing more critical updates to render first.

useSyncExternalStore Hook Tutorial

useSyncExternalStore is used to read data from an external store and subscribe to updates.

import React, { useSyncExternalStore } from 'react';

function useStore() {
  // Simulate external store
  const state = { count: 42 };
  return state;
}

function StoreComponent() {
  const store = useSyncExternalStore(useStore);

  return <div>Store Count: {store.count}</div>;
}

export default StoreComponent;
Enter fullscreen mode Exit fullscreen mode

Key Points:

  • useSyncExternalStore ensures that your component syncs with external stores in a way that guarantees stability across renders.

Outro

Congratulations! You’ve now learned about all the current React hooks and how to use them effectively. React hooks provide you with a powerful toolkit for building modern, efficient, and easy-to-maintain React applications. Keep experimenting with these hooks to improve your React skills and create amazing apps.

Happy coding!

Top comments (0)