4 min read

React JS - Custom Hooks

Author

Luka Žagar

Date

Category

Development

React JS - Custom hooks banner

What are the Hooks

React hook is one of the latest features of React JS that was added to the React library with the 16.8 version update. It allows you to use state and other important React features in your working components so that you don't even need to write custom classes anymore and provides you ease. When it comes to practical implementation, hooks are significantly more than it.

Hooks allow us to arrange the logic inside a component into reusable isolated units. Hooks are a natural fit for the React component model and give you the freedom to build your applications in a new way. Creating your custom hooks provides you the opportunity to distribute features beyond all components of your applications and even across different applications. Therefore, it saves time and increases your productivity in building more React applications. Let me give you a quick example of a React Hook here.

import React, {useState} from 'react'; function Example() { // Declare a new state variable, which we'll call "count" const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }

In the above code snippet, useState is the hook. For the time being, don’t hesitate if the above snippet doesn’t make sense to you. We’ll know more about the hook in this article later on. However, you can always check the official documentation of React hooks.

Benefits of Using Hooks

Being a React JS developer, you must get a wide range of advantages while using hooks. It is much evident that hooks are going to make better-creating components. Let me shed light on some of the significant benefits of a custom hook.

  • • Hooks give you the opportunity of writing clean and more concise code.
  • • No doubt that developers like less code while building an application. Hooks trim the codes and make your program more readable and robust.
  • • Less code-more productivity. Hooks help you from writing more lines of code and add more value to your productivity.
  • • Hooks are portable and reusable. You can use a custom hook anywhere in your application. That is a big plus for sure.
  • • Hooks don't contain any breaking changes. It's entirely backward compatible.
  • • Hooks don't displace your understanding of React concepts. Instead, Hooks provide a more direct API to the React concepts you already know: props, state, context, refs, and lifecycle.

Now, allow me to show you how a custom hook helps us. I am going to create a class version of our canonical document title effect and show you the difference between how it did use an npm-installed Hook that does precisely the same thing with fewer codes.

Using React State Hook

import React from 'react'; class Counter extends React.Component { constructor() { this.state = { count: 0 }; this.incrementCount = this.incrementCount.bind(this); } incrementCount() { this.setState({ count: this.state.count + 1 }); } componentDidMount() { document.title = `You clicked ${this.state.count} times`; } componentDidUpdate() { document.title = `You clicked ${this.state.count} times`; } render() { return ( <div> <p>You clicked {this.state.count} times</p> <button onClick={this.incrementCount}>Click Me</button> </div> ); } } export default Counter;

Using React Custom Hook

import React, {Component, useState} from 'react'; import useDocumentTitle from '@rehooks/document-title'; function Counter() { const [count, setCount] = useState(0); const incrementCount = () => setCount(count + 1); useDocumentTitle(`You clicked ${count} times`); return ( <div> <p>You clicked {count} times</p> <button onClick={incrementCount}>Click me</button> </div> ) } export default Counter;

Both the above snippet perform the click counts on a browser, but you can see how the use of hook made it easier and more readable. However, it did reduce the number of lines and improved the testability of the application.

Rules for Creating Custom Hooks

You have already known about the several advantages of custom hooks. However, there are a few conventions for creating custom hooks. It would be best if you keep them in mind.

  • • You cannot call a hook inside from a nested loop, function, or condition.
  • • A hook should always be placed at the top level of your component.
  • • Hooks cannot work from a regular function. So, don’t call a hook from a regular function.
  • • A custom Hook can invoke another Hook.

What Kinds of Hooks Exist Within the React

React Hooks are mainly classified into two types. One is the Built-in Hook, and the other one is Custom Hook. The APIs for built-in hooks come with the standard library. According to React's official documentation, built-in hooks are two types: Basic Hooks and Additional Hooks. Let me give you the list of them.

Basic Hooks

  • ➔ useState
  • ➔ useEffect
  • ➔ useContext

The basic hooks useState, useEffect, useContext are used for different purposes. For instance, the useEffect API is used for cleaning up an effect, timing of effects, or conditionally firing an effect. It accepts a function that contains imperative, possibly impactful code.

useEffect(didUpdate);

Additional Hooks in ReactJS

ReactJS has some additional hooks. Some of them are derived from bare hooks. You must understand and practice the basic one to understand the additional hooks. Let me shed light on additional hooks.

useReducer

The useReducer hook is an alternative to the useState hook. This hook accepts a reducer type argument and returns the current state paired with the dispatch function. The useReducer hook permits you to optimize performance for components that trigger deep updates because you can pass dispatch down instead of callbacks. The naive way to initialize the useReducer hook is below.

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

useCallback

The useCallback hook is compelling when you pass callbacks to optimized child components that rely on reference equality to prevent unnecessary renders. The useCallback function returns a memorized callback.

const memoizedCallback = useCallback( () => { doSomething(a, b); }, [a, b], );

useMemo

The useMemo function also returns a memorized value like useCallback. Hence, you pass a ‘create’ function and an array of dependencies; the useMemo recalculates the memorized data if it finds any changed dependencies. This optimization process makes your code efficient in each individual render.

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

useRef

The useRef returns a changeable ref object whose .current attribute is initialized to the passed argument (initialValue). The returned object will persevere for the entire lifetime of the component. In other words, the useRef is like a container that can hold a mutable value in its .current property.

const refContainer = useRef(initialValue);

Remaining Hooks

  • ➔ useImperativeHandle
  • ➔ useLayoutEffect
  • ➔ useDebugValue

How the React JS Custom Hooks are Made

Earlier in this article, I've discussed the custom hook and some of its benefits. Now, I'll shed light on creating custom hooks in React. As you all already know, a custom React Hook is a crucial tool that lets you score special, unique functionality to your React applications.

One of my favorite features is the dark mode on a website. It gives a minimalistic look to a website or application. One can switch back to the general view if need.

Let's step ahead and see how to build such a hook

import { useEffect } from 'react'; // Already created the useMediaQuery hook earlier import useMediaQuery from './useMediaQuery'; // Already created the useMediaQuery hook earlier import useLocalStorage from './useLocalStorage'; const useDarkMode = () => { const preferDarkMode = useMediaQuery(['(prefers-color-scheme: dark)'], [true], false); const [enabled, setEnabled] = useLocalStorage('dark-mode', preferDarkMode); useEffect(() => { if (enabled) { document.body.classList.add('dark'); } else { document.body.classList.remove('dark'); } }, [enabled]); return [enabled, setEnabled]; }; export default useDarkMode;

In the above program, I have created the custom hook useDarkMode similar to a basic JavaScript function. Please note: useMediaQuery and useLocalStorage are previously made custom hooks. Here useMediaQuery checks the user's browser preference for dark mode and useLocalStorage initialize, store, and persist the current state (dark or light mode) in LocalStorage.

One more important thing to remember, putting the keyword use in front of a custom hook is a convention. Except it React wouldn't be able to check for violations of rules of Hooks automatically.