DEV Community

Cover image for React Hooks: Cheat Sheet, with examples
alakkadshaw
alakkadshaw

Posted on • Originally published at deadsimplechat.com

React Hooks: Cheat Sheet, with examples

In this article we are going to learn about react Hooks, What are the types of hooks, built-in hooks, how you can combine multiple hooks to create your own hooks

What are Hooks?

To understand react hooks, let us first consider what are functional components?

Functional components at their core are functions, and as with all javascript functions you can use one function inside of another function.

Hooks are functions that let you use different react features in your components. You can import built-in hooks or create your own custom hooks by combining one or more built in hooks

This article is brought to you be DeadSimpleChat, Chat API and SDK for website and Apps. Using which you can easily add in-app messaging to your app

Let us learn about built in hooks and how you can combine them to create your own hooks with examples

Types of built-in hooks

State Hooks

  • useState

  • useReducer

Context Hooks

  • useContext

Ref Hooks

  • useRef

  • useimperativehandle

*Effect Hooks
*

  • useEffect

  • useLayoutEffect

  • useInsertionEffect

Performance Hooks

  • useMemo

  • useCallback

  • useTransition

  • useDeferredValue

Other Hooks

  • useDebugValue

  • useId

  • useSyncExternalStore

Creating your own Hooks

State Hooks

React State basically lets a component remember the data, any data that you would like to store can be stored in State

State is a javascript Object, that stores the data that is specific to the component inside of which the state is defined.

To add State to a component, use one of the following hooks

  1. useState declares a state variable which can be assigned to any data and updated directly

  2. useReducer declares a state variable inside a reducer function with update logic

Now, let us look at some of the examples

Example 1:

initializing the state

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);
  // rest of the component

}
Enter fullscreen mode Exit fullscreen mode

Here we are initializing state using the useState hook. The hook is a function that takes the initial state as an argument and returns an array with current state and a function to update the current state

accessing the state

To access the state just refer to the variable that you have defined while initializing the state, like so

<p>
    the count = {count}
</p>
Enter fullscreen mode Exit fullscreen mode

updating the state

simply call the update function and assign the new value of state to the function

setCount(count + 1);
Enter fullscreen mode Exit fullscreen mode

Note: The component re-renders whenever the state is updated

Example 2:

Let us look at another example with useReducer . When you have many state updates across many event handlers it can get overwhelming.

In these cases you can consolidate all the state logic outside your component in a single function called the reducer

Reducer is a pure function that takes the current state and an action then returns the new state

import React, { useReducer } from 'react';

// current state and action are recieved and new state is returned
const counterReducerFunc = (state, action) => {
  switch (action.type) {
    case 'increase':
      return { count: state.count + 1 };
    case 'decrease':
      return { count: state.count - 1 };
    default:
      throw new Error(`This action is not known: ${action.type}`);
  }
};

const Counter = () => {

  const [state, dispatch] = useReducer(counterReducer, { count: 0 });

  return (
    <div>
      Count: {state.count}
      <button onClick={() => dispatch({ type: 'increase' })}>Add</button>
      <button onClick={() => dispatch({ type: 'decrease' })}>Subtract</button>
    </div>
  );
};

export default Counter;
Enter fullscreen mode Exit fullscreen mode

Context Hooks

Context lets you pass the data from far away (distant ) parents to child with passing it as props

As an example, Your App's top level component can pass the current UI theme to all components below no matter how deep.

With react context you are able to avoid what is called as 'prop drilling' where you passing down the data from one component to its child, then from child component to its child component

With context all the data is provided to every component that subscribes to the context

  1. useContext reads and subscribes to a context

Example

Let us understand the useContext with the help of an example

First, we are going to create a context by using React.createContext() method

const SomeContext = React.createContext();
Enter fullscreen mode Exit fullscreen mode

Providing value to react context

The SomeContext.Provider component is used to provide a context value to all the children in the component tree

You can then place the SomeContext.Provider anywhere in the tree where you need to access the value

Consuming the Context value with useContext

To access the value from context simply use the useContext Hook inside your component

useContext takes the context Object that is 'SomeContext' here and returns the current context value like so

const ChildComponent = () => {
  const currentContextValue = useContext(SomeContext);

  return <p>{CurrentContextValue}</p>; // "We have electricity"
};
Enter fullscreen mode Exit fullscreen mode

useContext provides the context value directly to the child components without the need to pass the data using props.

Ref Hooks

The Refs lets a component hold a value that is not needed for rendering.

This value can be a DOM node or a timeout ID. Unlike a state updating a ref does not re render a component.

Refs are sort of an escape hatch from the react paradigm,

Refs can be useful when working with non react systems like Rest APIS, or to store previous state values, accessing the DOM directly or keeping any mutable values.

There are two hooks that deal with refs

  1. useRef declares a ref and you can hold any value in it
  2. useImperativeHandle lets you customize the ref exposed by the component. This hook is rarely used

Let us look at some examples to better understand this

Example

Creating a Ref

you can initialize the ref like this

const exampleRef = React.useRef();
Enter fullscreen mode Exit fullscreen mode

The ref object here that is exampleRef will persist throughout the lifetime of the component

accessing the values inside of a Ref

You can easily access the values inside of the Ref by using the .current property like

exampleRef.current = "We got the power";
console.log(exampleRef.current); //outputs "We got the power";
Enter fullscreen mode Exit fullscreen mode

Accessing DOM elements

In this example we are going to access a DOM node directly for something that can't be done in react declarative

lets see the example:

import React, { useRef } from 'react';

const SampleComponent = () => {
  const inputRef = useRef();

  const handleClick = () => {
    inputRef.current.focus();
  };

  return (
    <div>
      <input ref={inputRef} type="text" />
      <button onClick={handleClick}>On button click focus on the input tab</button>
    </div>
  );
};

export default SampleComponent;
Enter fullscreen mode Exit fullscreen mode

In this example we have input element to the inputRef ref and when the handleClick function is called it focuses on the input element using the inputRef.current.focus() method

Effects Hooks

Effects lets a component connect to and synchronize with external systems

This includes dealing with DOM, widgets that were written using a different UI library and other non react code.

Basically, useEffect lets you perform side effects in functional components. This includes interaction with outside of the component like data fetching, subscriptions, manual DOM manipulations etc.

Effects are an escapse hatch from the react ecosystem. So, do not use effects to orchestrate the data flow of your application as this might defeat the basis of using react and create multiple problems.

If you are not interacting with systems outside of React, you might not need to use Effect.

Let us look at examples to better understand the useeffect hook:

import React, { useEffect } from 'react';

const CoolComponent = () => {
  useEffect(() => {
    console.log('Rendering the component on the display');
  });

  return <h1>using the useEffect </h1>;
};

export default CoolComponent;
Enter fullscreen mode Exit fullscreen mode

In this example when the CoolComponent is rendered, the console.log statement written within the function will print the 'Rendering the component on the display'

Now, let us look at two other variations of useEffect

useLayoutEffect and

useInsertionEffect

useLayoutEffect runs similarly to the useEffect but runs synchronously after all the DOM mutations are done. This makes it a good tool for reading the layout from the DOM and re-rendering

So, if you need to measure a DOM node and then cause a synchronous re render, you can use the useLayoutEffect

useInsertionEffect is a react hook designed for developers working on CSS in JS libraries

Using this hook you can inject styles into the DOM before layout effects are fired, ensuring that these styles are available immediately when the component renders

the useInsertionEffect accepts a setup function and an optional dependency array similar to other hooks

Performance Hooks

Skipping unnecessary work is a common way to optimize re-rendering performance.

That is if the data has not changed from the previous re-render, you can tell react to skip the re-render or to skip the calculations thus saving resources

React provides several hooks to optimize the performance of your components and these are:

To skip calculations and avoid re-rendering of components you can use

  1. useMemo :Lets you cache the result of an expensive calculation

  2. useCallback : Lets you cache a function definition before passing it down to an optimized component

Sometimes, you can't skip the re-rendering because the screen needs to update.

In this case you can improve performance by separating the blocking updates that must be synchronous from non-blocking updates which do not need to block the UI

In these cases you can use one of the following hooks

useMemo

useMemo memorizes the result of a function. let us learn more about this using an example

import React, { useMemo } from 'react';

const CoolComponent = ({ values }) => {
  const expensiveCalculation = useMemo(() => {
    return values.reduce((big, expensive) => big + expensive, 0);
  }, [values]);

  return <div>{expensiveCalculation}</div>;
};

export default CoolComponent;

Enter fullscreen mode Exit fullscreen mode

In the above example useMemo memorizes the result of the expensiveCalculation and only perform the calculation if the props change

useCallback

useCallback is similar to useMemo but it returns a memorized version of the callback function that only changes if one the dependencies have changed

let us consider an example

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

const CoolComponent = () => {
  const [count, setCount] = useState(0);

  const increaseTheCount = useCallback(() => {
    setCount(count + 1);
  }, [count]);

  return <button onClick={increaseTheCount}>Increase the Count</button>;
};

export default CoolComponent;
Enter fullscreen mode Exit fullscreen mode

Here we are using the useCallback function to create a memorized version of the increaseTheCount function that only changes when the count changes

useTransition

useTransition is a hook that manages transitions on slow networks and devices.

It returns two values

  • a startTransition function and

  • an isPending boolean

Let us consider an example

import React, { useState, useTransition } from 'react';

const CoolComponent = () => {
  const [resource, setResource] = useState(null);
  const [startTransition, isPending] = useTransition();

  const GettingTheResource = () => {
    startTransition(() => {
      fetchResource().then(setResource);
    });
  };

  return (
    <div>
      <button onClick={GettingTheResource}>Get the Resource</button>
      {isPending ? 'Waiting...' : <ShowTheResource resource={resource} />}
    </div>
  );
};

export default CoolComponent;
Enter fullscreen mode Exit fullscreen mode

In the above example the usetransition is used to provide a smooth transition when the app is fetching a resource.

The isPending value can be used to show a loading screen while the resource is being fetched over the internet

useDeferredValue

Lets you defer a non-critical part of the UI and lets the other parts display first

Let us consider an example to better understand this

import React, { useState, useDeferredValue } from 'react';

const CoolComponent = () => {
  const [writeUp, setWriteUp] = useState('');
  const deferredValue = useDeferredValue(writeUp);

  return (
    <div>
      <input
        value={writeUp}
        onChange={e => setWriteUp(e.target.value)}
      />
      <SlowComponent setWriteUp={deferredValue} />
    </div>
  );
};

export default MyComponent;

Enter fullscreen mode Exit fullscreen mode

In this example the useDeferredValue is used to defer the value of the writeUp as that is less important than showing the input tab to the user first

Other Hooks

These are some of the other interesting built-in hooks available

  1. useDebugValue You can customize the label that the React DevTools displays for your custom with with useDebugValue

  2. useId Associate a unique ID with a component. You can use this with accessibility APIs

  3. useSyncExternalStore subscribe a component with an external store

Let us consider some examples to understand these hooks better

useDebugValue

import { useState, useDebugValue } from 'react';

function useChatStatus(userId) {
  const [isOnline, setIsOnline] = useState(null);

  // show a lable next to this hook in react Dev tools
  useDebugValue(isOnline ? 'Online' : 'Offline');

  return isOnline;
}
Enter fullscreen mode Exit fullscreen mode

In the above example we are using useDebugValue to show a custom hook useChatStatus in the react devtools

useId

useId is a react hook that can be used to create multiple unique ids that can be passed to accessibility attributes

let us consider an example to learn better

import { useId } from 'react';

function PasswordField() {
  // useId is used to generate a unique ID
  const passwordHintId = useId();

  return (
    <>
      <label>
        Password:
        <input type="password" aria-describedby={passwordHintId} />
      </label>
      <p id={passwordHintId}>
        The password should contain at least 18 characters
      </p>
    </>
  );
}

export default function App() {
  return (
    <>
      <h2>Choose password</h2>
      <PasswordField />
      <h2>Confirm password</h2>
      <PasswordField />
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

In the example the useId is used to generate unique ids for the description paragraph of the password input. If the PasswordField is used multiple times across the app the generated ids will not clash

Reason behind using useId for generating ids instead of an incrementing counter

you could simply increment the Global counter like count++ to generate new ids

The primary reason is that the useId maintains compatibility with the server rendering.

Creating custom hooks

You can also define your own custom hooks as javascript functions.

This involves extracting the duplicated logic that is being re used in multiple components into a separate function

The function will be called a Hook. The name of the hook always starts with the word use

There can be multiple hooks within a hook, like there can be multiple functions inside of a function

The returned values can be anything like functions, state, or any other value that you want to share between components

let us create the useOnlineUserStatus Hook as an example to better understand this topic

What is the Shared Logic In this case the shared logic is whether the user is online or not. This shared logic can be useful to multiple components

Create a function with the starting keyword use As we have already decided that the name of our hook will be useOnlineUserStatus.

function useOnlineUserStatus() {

}
Enter fullscreen mode Exit fullscreen mode

Moving the shared logic into the function that we just created

import { useState, useEffect } from 'react';

function useOnlineUserStatus() {
  const [isUserOnline, setIsUserOnline] = useState(true);

  useEffect(() => {
    function handleOnline() {
      setIsUserOnline(true);
    }

    function handleOffline() {
      setIsUserOnline(false);
    }

    window.addEventListener('online', handleOnline);
    window.addEventListener('offline', handleOffline);
    return () => {
      window.removeEventListener('online', handleOnline);
      window.removeEventListener('offline', handleOffline);
    };
  }, []);

  return isUserOnline;
}
Enter fullscreen mode Exit fullscreen mode

return Here we are returning the data the other components might need that is the status of the user.

Using the Custom Hook in your code

You can use the custom hook in your component like any other hook

function ShowOnlineUserStatus() {
  const isUserOnline = useOnlineUserStatus();
  return <h1>{isOnline ? 'โœ… Online' : 'โŒ Disconnected'}</h1>;
}
Enter fullscreen mode Exit fullscreen mode

Thus we have created a custom hook

Conclusion

In this article I have covered a wide range of topics regarding the React Hooks, including types of hooks their use cases and how to use them in your code

I hope that you liked the article. Thank you for reading

Top comments (1)

Collapse
 
Sloan, the sloth mascot
Comment deleted