Creating and Using Custom Hooks

Tutorial 5 of 5

Creating and Using Custom Hooks

1. Introduction

The goal of this tutorial is to teach you how to create and use Custom Hooks in React. By the end of this tutorial, you will be able to extract component logic into reusable functions and share behaviors between different components.

Prerequisites

To fully grasp this tutorial, you need to have a basic understanding of React and JavaScript syntax, including ES6 features like arrow functions, and the use of state and effect hooks in React.

2. Step-by-Step Guide

A custom Hook is essentially a JavaScript function, but its name starts with 'use', and it can call other Hooks.

Why Custom Hooks

Custom Hooks allow us to reuse stateful logic between components. Before Hooks were introduced, this was done via render props and higher-order components. But custom hooks provide a much easier way to share logic between components.

Creating a Custom Hook

A custom Hook is a normal function which we've decided to call a Hook. It's a convention that our function name should begin with the word 'use'. If the function does call other Hooks, we must follow the rules of Hooks.

Let's create a custom Hook called useWindowWidth that will return the window's width.

import { useState, useEffect } from 'react';

function useWindowWidth() {
  const [width, setWidth] = useState(window.innerWidth);

  useEffect(() => {
    const handleResize = () => setWidth(window.innerWidth);
    window.addEventListener('resize', handleResize);
    return () => {
      window.removeEventListener('resize', handleResize);
    };
  }, []);

  return width;
}

In the above code, we've created a custom Hook that uses the useState and useEffect Hooks to track and update the window width.

3. Code Examples

Using a Custom Hook

Let's see how we can use the useWindowWidth hook we created above in a component.

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

function Component() {
  const width = useWindowWidth();

  return (
    <div>
      <p>Window width is: {width}</p>
    </div>
  );
}

export default Component;

In the code above, we imported our custom Hook and used it inside our functional component. The component will now always display the current window width, and update it whenever the window is resized.

4. Summary

In this tutorial, we've learned how to create and use Custom Hooks in React. We saw that Custom Hooks are a built-in feature in React that allows us to extract component logic into reusable functions. We also learned how to use the custom Hook in a React component.

Now that you understand Custom Hooks, a good next step would be to learn more about the other types of Hooks that React provides, like useContext, useReducer, and useMemo.

5. Practice Exercises

  1. Create a custom Hook useDocumentTitle that sets the document title to the given input. Use it in a component to set the document title.

  2. Create a custom Hook useLocalStorage that syncs a value with local storage. The Hook should return the current value and a function to update it.

Solutions:

  1. useDocumentTitle Hook:
import { useEffect } from 'react';

function useDocumentTitle(title) {
  useEffect(() => {
    document.title = title;
  }, [title]);
}

Component usage:

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

function Component() {
  useDocumentTitle('My new title');

  return (
    <div>
      <p>Check the document title!</p>
    </div>
  );
}

export default Component;
  1. useLocalStorage Hook:
import { useState, useEffect } from 'react';

function useLocalStorage(key, initialValue) {
  const [storedValue, setStoredValue] = useState(() => {
    try {
      const item = window.localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      return initialValue;
    }
  });

  const setValue = value => {
    try {
      setStoredValue(value);
      window.localStorage.setItem(key, JSON.stringify(value));
    } catch (error) {
      console.log(error);
    }
  };

  return [storedValue, setValue];
}

Component usage:

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

function Component() {
  const [name, setName] = useLocalStorage('name', 'Anonymous');

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

export default Component;

Make sure to practice creating your own custom Hooks and using them in different components to get a good grasp of this concept. Happy coding!