Top 5 React Hooks

Top 5 React Hooks

·

4 min read

React hooks were introduced in React 16.8 to use State and other React Features. It lets you hook into the features without needing to create Classes.

1. useState

This might be the first hook you heard about when learning React. It is very common and can be very useful.

As the name suggests it creates a State Variable. This hook helps us to preserve the variables even after the function exits.

import React, { useState } from 'react';

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

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

The hook returns two values: the current value and a function to update the value.


2. useEffect

Another common hook is the useEffect. This is similar to the componentDidMount in Class Components.

They are used to run side effects. They are mainly used when you want to perform any manipulations with every state change or when only a certain value changes.

Let's use the previous example and use useEffect to log the value of count every time it changes.

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

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

  useEffect(() => {
      console.log(count);
  }, [count]);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

You can also return a function from useEffect to do any clean up. It is executed when the component unmounts.

useEffect(() => {
  console.log(count);

  return () => {
    setCount(0);
  };
}, [count]);

3. useMemo

This hooks is used to keep expensive functions from running again and again. They return a memoized value and are updated only when one of the dependencies update.

Let us consider that we have two state variables and an resource intensive / expensive function that takes one of the variables as param.

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

const App = () => {
  const [count, setCount] = useState(0);
  const [todos, setTodos] = useState([]);
  const calculation = expensiveCalculation(count);

  useEffect(() => {
      console.log(count);
  }, [count]);

  const addTodo = (todo) => {
     setTodos(t => [...t, 'todo'];
  }

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me to increase Count
      </button>
      <button onClick={() => addTodo("Example Todo 1")}>
        Click me to set Todo
      </button>
    </div>
  );
}

const expensiveCalculation = (num) => {
  console.log("Calculating...");
  // Do some Intensive Task
  return num;
};

In the above example even though the calculation doesn't have anything to do with todo, we can see that the calculation is done for every render even when the count value hasn't been updated.

To fix this we can simply wrap the function in a useMemo hook and pass in count as the dependency.

const calculation = useMemo(() => expensiveCalculation(count), [count]);

This will make sure that the calculation is calculated only when the count value gets updated.


4. useCallback

The useCallback and useMemo Hooks are similar. The main difference is that useMemo returns a memoized value and useCallback returns a memoized function. Let's modify the above example to create a child component to visualize the use of useCallback better.

import React, { useState, useCallback } from 'react';
import Todos from "./Todos";

const App = () => {
  const [count, setCount] = useState(0);
  const [todos, setTodos] = useState([]);

  const addTodo = (todo) => {
    setTodos((t) => [...t, "todo"]);
  };

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me to increase Count
      </button>
      <Todos todos={todos} addTodo={addTodo} />
    </div>
  );
};
// Todos.js
import { memo } from "react";

const Todos = ({ todos, addTodo }) => {
  console.log("child render");
  return (
    <>
      <h2>My Todos</h2>
      {todos.map((todo, index) => {
        return <p key={index}>{todo}</p>;
      })}
      <button onClick={addTodo}>Add Todo</button>
    </>
  );
};

export default memo(Todos);

When we try to increase the count, we can see that the Todos component is also getting re rendered. It is because every time a component gets re-rendered, its functions get recreated. Due to this the addTodo function isn't the same function as before.

To prevent this, we can use the useCallback hook.

const addTodo = useCallback(() => {
    setTodos((t) => [...t, "New Todo"]);
  }, [todos]);

Now Todos will get re-rendered only when todos prop changes.


5. useRef

The useRef Hook allows you to persist values between renders.

It can be used to access a DOM element directly.

In React, we can add a ref attribute to an element to access it directly in the DOM.

Here's a simple example to see how you can access DOM elements using useRef.

import React, { useRef } from "react";

const App = () => {
  const inputElement = useRef();

  const focusInput = () => {
    inputElement.current.focus();
  };

  return (
    <>
      <input type="text" ref={inputElement} />
      <button onClick={focusInput}>Focus Input</button>
    </>
  );
};

export default App;

Apart from this, there is much more you can do with hooks. You can even create your own hooks. Check this doc from the React Docs site to learn more about how you can achieve it.

If you found this article helpful, do share it with your friends.