Mastering React Hooks: Everything you need to get started

Mastering React Hooks: Everything you need to get started

Unlocking the Potential of React Hooks for Seamless State Management and Component Logic

Hello everyone! In this blog, I'll be dissecting the most common React hooks that are heavily utilized in React application development.
There are two types of components in React: state components and functional components. Initially, React didn't support lifecycle features like constructor(), getDerivedStateFromProps(), render(), componentDidMount(), etc. That's where hooks come in. Hooks allows us to seamlessly integrate with React features such as state management and lifecycle methods in functional components.

There are seven hooks in React: useState, useEffect, useCallback, useMemo, useRef, useContext, and useReducer. Among these, useState and useEffect take center stage, accounting for approximately 90% of usage. Alongside these, we'll also explore useMemo and useRef, with a brief introduction to custom hooks. useCallback would require a complete blog to itself.

Let's dive in.

1. useState Hook

useState is the most common hook in React. As the name suggests, it handles state management in react.

In React, every component undergoes re-rendering upon state change.

Syntax:const [count, setCount] = useState(0);

In the above syntax:

  • count represents our state variable.

  • setCount is the function employed for updating the variable.

  • 0 denotes the initial value for the variable.

Syntax for Updating State:setCount(1)

The useState hook accommodates a wide array of data types including strings, numbers, booleans, arrays, objects, and any amalgamation thereof.

Example ofuseState:

import React, { useState } from 'react';

function Example() {
  const [count, setCount] = useState(0);

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

The provided code snippet creates a counter that increments upon button click.

2. useEffect Hook

The problem: Imagine we're fetching data from an API and storing it in a state variable. Each time this variable changes, it triggers a re-render of the component. This, in turn, prompts another API call, creating an infinite loop of requests.

Solution:useEffect Hook. ACode within the useEffect hook executes only during the initial render and subsequently whenever there's a change in the specified dependency.

Syntax:useEffect(() => {}, [dependency]);

Example:

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

function MyComponent({ id }) {
    const [data, setData] = useState(null);

    useEffect(() => {
        fetch('https://my-api.com/data/${id}*')
            .then(response => response.json())
            .then(data => setData(data));
    }, [id]);

    return React.createElement("div", null, "MyComponent renders here!");
}

In the above code we are sending an API request and 'id' is used as the dependency for the useEffect hook.

Top useEffect use cases:-

  1. Fetching API Data: Avoid making multiple requests to the server, particularly when dealing with user inputs like typing in a search field.

  2. Input Field Validation: Validate input fields efficiently, minimizing unnecessary validations triggered by every character change.

💡
Before we proceed, it's crucial to grasp a fundamental principle of React development: the key to crafting an optimized React application lies in minimizing the number of re-renders within a component. This optimization ensures that our application operates smoothly and efficiently, enhancing user experience. Several hooks we'll explore next are specifically designed to address this optimization challenge, empowering us to fine-tune our components for maximum performance.

3. useMemo Hook

The useMemo hook is used for memorization, Effectively storing solutions to computations. Simply put, it caches the result of a function and recalculates it only when its dependencies change. It is similar to useEffect hook, but it prevents from executing the code during the initial render. useMemo also reduces a state variable, if we try to achieve the same thing with useEffect.

As it doesn't result in any drastic improvement, it is rarely used.

Syntax: const memodVal = useMemo(() => {}, []);

Example:

import { useState, useMemo } from "react";
import ReactDOM from "react-dom/client";

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

  const increment = () => {
    setCount((c) => c + 1);
  };
  const addTodo = () => {
    setTodos((t) => [...t, "New Todo"]);
  };

  return (
    <div>
      <div>
        <h2>My Todos</h2>
        {todos.map((todo, index) => {
          return <p key={index}>{todo}</p>;
        })}
        <button onClick={addTodo}>Add Todo</button>
      </div>
      <hr />
      <div>
        Count: {count}
        <button onClick={increment}>+</button>
        <h2>Expensive Calculation</h2>
        {calculation}
      </div>
    </div>
  );
};

const expensiveCalculation = (num) => {
  console.log("Calculating...");
  for (let i = 0; i < 1000000000; i++) {
    num += 1;
  }
  return num;
};

In the above example, the expensive Calculation will not run on adding a todo, as it is wrapped inside useMemo hook.

4. useRef Hook

useRef hook is very different from other hooks. It mainly has 2 use cases:-

  1. It can be used to access a DOM element directly.

    Let us understand this with an example

     function App() {
       const inputElement = useRef();
    
       const focusInput = () => {
         inputElement.current.focus();
       };
    
       return (
         <>
           <input type="text" ref={inputElement} />
           <button onClick={focusInput}>Focus Input</button>
         </>
       );
     }
    

    In the above example, useRef is used to access the DOM element input by giving it a reference. We can do multiple operations with this element. For eg. here we are focusing the element on clicking a button.

It can be used to store a mutable value that does not cause a re-render when updated.

This can be helpful in various ways. We can count the number of times the component is rendered in our application.

function App() {
  const renderCounter  = useRef(0);
  renderCounter.current = renderCounter.current + 1;

  return (
    <>
    </>
  );
}

5. Custom Hooks

Hooks in React serve as reusable functions, empowering developers to create custom hooks tailored to their specific needs. By convention, all custom hooks must start with the keyword 'use'. For example, let us create a custom hook named useFetch, designed to streamline the fetching logic across multiple components.

const useFetch = (url) => {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetch(url)
      .then((res) => res.json())
      .then((data) => setData(data));
  }, [url]);

  return [data];
};

This is how you can easily create custom hooks.

In conclusion, these custom hooks, alongside built-in ones, elevate the power and versatility of functional components in React. They simplify development and enhance the flexibility of React applications.

That's a wrap. Please share your thoughts below, and stay tuned for more insightful content in the future. Until next time!