Getting started with Custom Hooks in React

Getting started with Custom Hooks in React

ยท

4 min read

React hooks are one of the reason why I prefer using React over any other library or framework. For people who are still new to React fundamentals, React Hooks are in-built functions that allow React developers to use state and lifecycle methods inside functional components, they also work together with existing code, so they can easily be adopted into a codebase. The way Hooks were pitched to the public was that they allow developers to use state in functional components but under the hood, Hooks are much more powerful than that. They allow React Developers to enjoy the following benefits:

  • Improved code reuse
  • Better code composition
  • Better defaults
  • Sharing non-visual logic with the use of custom hooks
  • Flexibility in moving up and down the components tree.

The most commonly used React hooks are:

  • useState()
  • useEffect()
  • useContext()
  • useReducer()
  • useMemo()
  • useCallback()

You can read more about react hooks ๐Ÿ‘‰ here

However, in this article we'll be discussing about writing your own custom hooks. Yes, React provides this functionality wherein developers can write their own version of react hooks. It is a great way to share common code among various function components.

Need for Custom Hooks ๐Ÿ˜Ž๐Ÿ˜Ž

There might be instances where you have been using the same repetitive and redundant stateful logic inside multiple components. We were able to handle this situation by relying on Render props and Higher Order Components. But with hooks, we can do it in a much simpler and cleaner way, Thanks to the Custom hooks.

Custom Hooks are normal javascript functions which can use other hooks inside of it and contain a common stateful logic that can be reused within multiple components. These functions are prefixed with the word use.

Let's take a look at few examples to have a much better understanding.

useDocumentTitle

useDocumentTitle is our first custom hook which we'll be implementing.

The requirement is very simple i.e we need to create a component with a custom hook where we have an input field. Based on the text inside the input field, the document title should change. So let's get started.

We start by defining our input text field along with a useState hook to handle the component state.

import "./styles.css";
import { useState } from "react";

export default function App() {
  const [value, setValue] = useState("");

  return (
    <div className="App">
      <input
        value={value}
        onChange={(event) => {
          setValue(event.target.value);
        }}
      />
    </div>
  );
}

Now we'll create a function which will act as our custom hook.

import {useEffect} from 'react'

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

export default useDocumentTitle

Note : It is important to add use keyword if you want to use the function as a custom hook.

Our useDocumentTitle function takes an input value and if that input changes it'll update the document title. Nothing new here. But, the important thing is that now this function can be used in various other components which reduces the code size considerably instead of writing the same code again.

The only thing left is to import this function inside the component where you wish to use it.

import "./styles.css";
import useDocumentTitle from "./hooks/useDocumentTitle";
import { useState } from "react";

export default function App() {
  const [value, setValue] = useState("");

  useDocumentTitle(value);
  return (
    <div className="App">
      <input
        value={value}
        onChange={(event) => {
          setValue(event.target.value);
        }}
      />
    </div>
  );
}

useLocalStorage

useLocalStorage is another great hook to use in your code wherein you need to store user input values.

The requirement for useLocalStorage is that you need to create a component with an input field wherein the input value gets stored in the local storage as the user in typing. So, let's get started.

Here, we'll first create our custom hook function.

import { useEffect, useState } from "react";

function getStoredValue(key, initialValue) {
  let localValue = JSON.parse(localStorage.getItem(key));
  if (localValue) return localValue;

  if (initialValue instanceof Function) return initialValue();

  return initialValue;
}

function useLocalStorage(key, initialValue) {
  const [value, setValue] = useState(() => {
    return getStoredValue(key, initialValue);
  });

  useEffect(() => {
    localStorage.setItem(key, JSON.stringify(value));
  }, [key, value]);

  return [value, setValue];
}

export default useLocalStorage;

Here, the useLocalStorage function takes two arguments, namely: key and initialValue, and will serve as our custom hook. Now we know that useState is used to define the state variables by providing an initial value. So we use the getStoredValue function to get the saved value incase the component was used before and there is already a value saved in the local storage. The getStoredValue function serves this purpose. After that we defined a useEffect hook to save the input value in local storage.

The only thing left is to import it inside our component with input field.

import useLocalStorage from "./hooks/useLocalStorage";
import "./styles.css";

export default function App() {
  const [value, setValue] = useLocalStorage("name", "");

  return (
    <div className="App">
      <input 
      value={value} 
      onChange={(event) => setValue(event.target.value)} />
    </div>
  );
}

Inside the component, we call our custom hook by providing the key (to store in local storage) and initial value .

Conclusion

In this article we learned about creating our own custom hooks. There is no limit to what you can achieve by implementing your own hooks. I'll recommend you to use custom hooks wherever possible as designing your own hooks would greatly help you in improving the code quality.

ย