We're planting a tree for every job application! Click here to learn more

Working with advanced React Hooks

Damilola Adedoyin Ezekiel

7 Jan 2022

7 min read

Working with advanced React Hooks
  • React

Introduction

Hooks are a new addition in React that lets you use state and other React features without writing a class. Hooks are functions that let you “hook into” React state and lifecycle features from function components.

Before the release of Hooks in React, you can only manipulate or update state using the lifecycle methods present in class components but using hook allows you to utilize the power of React without writing classes. Hooks offer a powerful and expressive new way to reuse functionality between components.

This article will cover the concept of hooks from basic to advanced and at the end of this article, you will understand when and how to use the different types of React Hooks in your application.

Rules of Hooks

There are rules guiding the usage of hooks and to avoid your codes from throwing errors, these rules have to be followed.

  • Hooks must be called inside a function or component body.
  • Do not call hooks conditionally, inside loops, or nested functions.
  • When naming hooks, it should start with the prefix 'use'. This applies to both custom hooks and the ones provided by React.
  • When using hooks, the component has to be in uppercase.

Working with Hooks

React provides different ways of using Hooks in applications. This means we can use different hooks in our application, depending on what we are trying to achieve. React also gives us the power to create custom hooks which allows us to reuse stateful logic. Isn't that awesome!!!

Let's get started by taking a look at the different Hooks in React 🚀

  • useState hook

    The useState hook is used to manage and update state in React applications. It gives us an array to work with and this array is made of two values: the state and the setter function and this setter function is what we use to update our state. The useState hook also takes in a value of what the default state is.

Example:

import React, { useState } from "react";

const App = () => {

  const [text, setText] = useState(false);

  return (
    <div>
      <h2>{text === true ? "Sign In" : "Sign Up"}</h2>
      <button onClick={()=>setText(!text)}>Change Text.</button>
    </div>
  );
};
export default App;

View it live on CodeSandbox.

In the example above, the button updates the content of the h2 element whenever we click on it and this is only possible because of the useState hook.

First, we initialize a new state variable named text and a setter function named setText and then assign both variables to useState.

We then return two elements, the h2 element holds the value of the state itself and we declare a conditional statement to check if the state which is text equals true. If yes we want to display either Sign In or Sign Up

The button element takes in an onClick property which value is the setter function that we use to update our state. Each time we click on this button, React will re-render the component thereby passing the correct value to the h2element.

  • useEffect hook

The useEffect hook allows you to perform side effects in a function. Side effects include: fetching data from an API, changing DOM elements, pushing contents into an array, etc.

useEffect performs the function of componentDidMount, componentDidUpdate, and componentWillUnmount combined.

By default, useEffect runs after every re-render in the component, and most times we only want useEffect to run only when it is mounted. To solve this problem, we have to include a dependency array in the useEffect and this comes very handily in cases where we want to get data from an API. We do not want to call the API every time the component re-renders, we only want to call it as soon as useEffect is mounted.

useEffect ( () => {
  //do something here
}, [])

Let's take a look at how useEffect works with an example:

import React, { useState, useEffect } from "react";

const App = () => {
  const [products, setProducts] = useState({});

  const fetchData = async () => {
    const response = await fetch("https://fakestoreapi.com/products?limit=5");
    const data = await response.json();
    setProducts(data)
  };

  useEffect(() => {
    fetchData();
  }, []);
  return (
    <div className="App">
      {products.map(({image, title, price,id})=>(
        <div key={id} className="container">
        <img src={image} alt="store" />
        <p>{title}</p>
        <p>{price}</p>
        </div>
      ))}
     
    </div>
  );
};

export default App;

screencapture-0jyjd-csb-app-2021-12-09-10_21_55.png

View it live on CodeSandbox .

From the example above, we are fetching data from a fake API, we map through the result gotten from the API and finally, we return the result.

  • useReducer Hook

The useReducer hook is a hook that is used for state management. You might be wondering why the useReducer hook is performing the same function as the useState hook.

Both the useReducer hook and useState hook are used for state management but the usage of either of them is based on the size of your application. useReducer is usually preferable to useState when you have complex state logic that involves multiple sub-values. It also lets you optimize performance for components that trigger deep updates because you can pass dispatch down instead of callbacks.

The useReducer hook syntax is quite similar to useState, only it takes in two parameters which are the reducer function and the initial state. The value of the initial state could be anything depending on what we're trying to initialize. It could be a number, function, array, object, etc.

Let's take a look at a demo of how to implement the useReducer hook in our code by building a simple counter.

import React, { useReducer } from "react";

function reducer(state, action) {
  switch (action.type) {
    case "increment":
      return state + 1;
    case "decrement":
      return state - 1;
    default:
      return state;
  }
}

const App = () => {
  const [count, dispatch] = useReducer(reducer, 0);
  return (
    <div className="App">
      <h1>Count: {count} </h1>
      <button onClick={() => dispatch({type:"decrement"})}>-</button>
      <button onClick={() => dispatch({type:"increment"})}>+</button>
    </div>
  );
};
export default App;

First, we declare an array that holds the current state and dispatch function and then assign it to the useReducer hook. The useReducer hook takes in two values which are the reducer function and an initial state. In this case, the initial state is 0.

Next, we return JSX elements that return values from the function. The h1 element holds the value of count and then two buttons that increase and decrease the value of count. Each of the buttons will have an onClick property and we will pass the dispatch function to it. The dispatch function also holds a parameter that represents the type of action we want to carry out, in this case, we want to increment and decrement.

Finally, we declare our reducer function outside the main function. This reducer function takes in two parameters which are state and action. Now we want to use a switch statement to check the type of action that has been declared in the dispatch function. So, if the type of action is increment, we want to increase the state by 1, and if it is decrement, we want to decrease the state by 1, else nothing should happen.

  • useContext

The useContext hook allows us to work with React's Context API, which itself is a mechanism to allow us to share data within its component tree without passing through props. It basically removes prop-drilling!

The useContext hooks accepts a context object which is the value returned from React.createContext and returns the current context value, as given by the nearest context provider for the given context.

Let's take a look at how it works by building a random password generator 🚀

import React,{useContext, createContext, useState} from "react";

const RandomPasswordContext = createContext();
const SetRandomPasswordContext = createContext();

function RandomPassword() {
  const randomPassword = useContext(RandomPasswordContext);
  return <div>Password: {randomPassword}</div>;
}

function PasswordGenerator() {
  let text =""
  let characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  const setRandomNumber = useContext(SetRandomPasswordContext);
  const generateRandomNumber = () => {
      for (let i = 1; i < 7; i++){
    setRandomNumber (text+=characters.charAt(Math.floor(Math.random() * characters.length)));
  }
};
  return <button onClick={generateRandomNumber}>Generate Random Password</button>;
}

const App = () => {
  const [randomNumber, setRandomNumber] = useState(0);

  return (
    <div>
      <RandomPasswordContext.Provider value={randomNumber}>
        <SetRandomPasswordContext.Provider value={setRandomNumber}>
          <RandomPassword />
          <PasswordGenerator />
        </SetRandomPasswordContext.Provider>
      </RandomPasswordContext.Provider>
    </div>
  );
}

export default App

  • useRef

The useRef hook returns a mutable ref object, where the .current property is initialised to the passed argument(initial value). This hook makes it possible to access DOM nodes within functional component. We can use it as follows:

import React, {useRef} from "react";

const refContainer = useRef(initialValue)

This hook is used to deal with references to element and component in react. We can set a reference by passing the ref props to an element.

Let's take a look at the most common example on how to use the useRef hook 🚀

import React, { useEffect, useRef } from "react"

const App = () => {
  const inputEl = useRef(null);
  useEffect(() => {
    inputEl.current.focus();
  }, []);
  return <input ref={inputEl} type="text" />;
}

export default App;

From the example above, we are accessing the input element and we want to focus on the input element as soon as the component is mounted.

  • useCallback

  This Hook allows us to pass an inline callback function, and an array of dependencies, and will return a memoized version of the callback function. It is useful for when we want to prevent a function from being created on every render.

import React, {useState} from "react";

const Counter = ({increment}) => {
  return <button onClick={increment}>increase</button>;
};
const App = () => {
  const [count, setCount] = useState(0);
  return (
    <div>
      <p>Count : {count}</p>
      <Counter increment={()=>setCount(count + 1)} />
    </div>
  );
};

export default App;

In the example above, every time the App component refreshes, the setCount function will be rendered. We can use the useCallback hook in order to prevent this from happening.

import React, { useState, useCallback } from "react";

const Counter = ({increment}) => {
  return <button onClick={increment}>increase</button>;
};
const App = () => {
  const [count, setCount] = useState(0);
  const increment = useCallback(()=>{
    setCount(c => c + 1)
  },[setCount])
  return (
    <div>
      <p>Count : {count}</p>
      <Counter increment={increment} />
    </div>
  );
};

export default App;

  The useCallback Hook is useful when passing callbacks to optimised child components. It works similarly to the useMemo Hook, but for callback functions.

 - #### useMemo

  Memoization is an optimisation technique where the result of a function call is cached, and is then returned when the same input occurs again. The useMemo Hook allows us to compute a value and memoize it. We can use it as follows:

  import { useMemo } from 'react'

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

  The useMemo Hook is useful for optimisation when we want to avoid re-executing expensive operations.

  • useLayoutEffect

  This Hook is identical to useEffect, but it only fires after all Document Object Model (DOM) mutations. We can use it as follows:

  import { useLayoutEffect } from 'react'

  useLayoutEffect(didUpdate)

  The useLayoutEffect Hook can be used to read information from the DOM.

  Use the useEffect Hook when possible, because useLayoutEffect will block visual updates and slow down your application.

  • useDebugValue

  This Hook can be used to display a label in React DevTools when creating custom Hooks. We can use it as follows:

  import { useDebugValue } from 'react'

  useDebugValue(value)

You can use this Hook in custom Hooks to display the current state of your Hooks, as it will make it easier to debug them.

To learn more about React hooks, you can check out the official documentation

Thanks for reading 🚀 🚀

Did you like this article?

Damilola Adedoyin Ezekiel

Developer Advocate and Technical Writer

See other articles by Damilola

Related jobs

See all

Title

The company

  • Remote

Title

The company

  • Remote

Title

The company

  • Remote

Title

The company

  • Remote

Related articles

JavaScript Functional Style Made Simple

JavaScript Functional Style Made Simple

Daniel Boros

12 Sep 2021

JavaScript Functional Style Made Simple

JavaScript Functional Style Made Simple

Daniel Boros

12 Sep 2021

WorksHub

CareersCompaniesSitemapFunctional WorksBlockchain WorksJavaScript WorksAI WorksGolang WorksJava WorksPython WorksRemote Works
hello@works-hub.com

Ground Floor, Verse Building, 18 Brunswick Place, London, N1 6DZ

108 E 16th Street, New York, NY 10003

Subscribe to our newsletter

Join over 111,000 others and get access to exclusive content, job opportunities and more!

© 2024 WorksHub

Privacy PolicyDeveloped by WorksHub