React JS - Custom Hooks
Author
Luka Žagar
Date
Category
Development
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.