Codecademy Logo

Advanced React: Custom Hooks

The Effect Hook

After importing useEffect() from the 'react' library, we call this Hook at the top level of a React function definition to perform a side effect. The callback function that we pass as the first argument of useEffect() is where we write whatever JavaScript code that we’d like React to call after each render.

import React, { useState, useEffect } from 'react'; function TitleCount() { const [count, setCount] = useState(0); useEffect(() => { document.title = `You clicked ${count} times`; }, [count]); return <button onClick={(prev) => setCount(prev + 1)}>+</button>; }

Rules for Using Hooks

There are two main rules to keep in mind when using Hooks:

  1. Only call Hooks from React function components.
  2. Only call Hooks at the top level, to be sure that Hooks are called in the same order each time a component renders.

Common mistakes to avoid are calling Hooks inside of loops, conditions, or nested functions.

// Instead of confusing React with code like this: if (userName !== '') { useEffect(() => { localStorage.setItem('savedUserName', userName); }); } // We can accomplish the same goal, while consistently calling our Hook every time: useEffect(() => { if (userName !== '') { localStorage.setItem('savedUserName', userName); } });

Effect hooks

Effect hooks are useful for performing “side effects” after render such as fetching data and reacting to state changes.

useEffect(() => { fetch("https://some-api.com/get-some-user-information") .then(response => { console.log(response) }) .catch(error => { console.log(error) }); }, [])

Effect Dependency Array

The dependency array is used to tell the useEffect() method when to call our effect.

By default, with no dependency array provided, our effect is called after every render. An empty dependency array signals that our effect never needs to be re-run. A non-empty dependency array signals to the Effect Hook that it only needs to call our effect again when the value of one of the listed dependencies has changed.

useEffect(() => { alert('called after every render'); }); useEffect(() => { alert('called after first render'); }, []); useEffect(() => { alert('called when value of `endpoint` or `id` changes'); }, [endpoint, id]);

Custom Hooks

Custom Hooks are JavaScript functions that make use of other hooks, follow the rules of hooks, and whose names begin with use. Custom hooks are simply a convention and the programmer can decide what they do and what they return.

The provided example is from the Playing Hooky project. This custom hook changes the page’s appearance to “dark” or “light” mode while providing the current theme value for use elsewhere in the application.

const useTheme = () => { // "theme" state with a default value of "light". const [theme, setTheme] = useState("light"); // Changes the pages CSS styling. useEffect(() => { document.documentElement.setAttribute("data-theme", theme); }, [theme]); // Function executed in the application. const onToggleTheme = () => { setTheme((previousTheme) => previousTheme === "light" ? "dark" : "light"); }; // Makes the function available for use in the application. return {theme, onToggleTheme}; }

Use of Custom Hooks

Custom hooks have many benefits. They:

  • Allow code to be abstracted
  • Hide complex logic
  • Allow stateful logic to be reused between multiple components