The Basics of React Hooks: A Comprehensive Guide - Part 1

The Basics of React Hooks: A Comprehensive Guide - Part 1

useState , useEffect , useRef

React Hooks, introduced in React 16.8, have changed the way we write functional components in React applications. They allow us to use state and other React features without writing a class. This blog aims to demonstrate the most commonly used hooks: useState, useEffect, and useRef, providing a foundation for building react applications.

TheuseState Hook

Why Use State Instead of Normal javascript variable let or const

  1. Reactivity: State variables are reactive. When state changes, React re-renders the component to reflect those changes. Normal variables don’t trigger re-renders.

  2. Persistence: State persists between re-renders, while normal variables get reset.

  3. Consistency: React ensures state consistency across re-renders, providing a reliable and predictable way to manage dynamic data.

     import React, { useState } from 'react';
    
     function ExampleComponent() {
       // Normal state update pattern
       const [countNormal, setCountNormal] = useState(0);
    
       // prevState-based state update pattern
       const [countPrevState, setCountPrevState] = useState(0);
    
       // Normal state update when clicking the "Click me (Normal)" button
       const handleNormalClick = () => {
         // Increment count by 1
         setCountNormal(countNormal + 1);
       };
    
       // prevState-based state update when clicking the "Click me (prevState)" button
       const handlePrevStateClick = () => {
         // Increment count by 1 based on previous state
         setCountPrevState((prevState) => prevState + 1);
       };
    
       return (
         <div>
           <div>
             <p>You clicked {countNormal} times (Normal)</p>
             <button onClick={handleNormalClick}>
               Click me (Normal)
             </button>
           </div>
           <div>
             <p>You clicked {countPrevState} times (prevState)</p>
             <button onClick={handlePrevStateClick}>
               Click me (prevState)
             </button>
           </div>
         </div>
       );
     }
    
     export default ExampleComponent;
    

    When you need to update a state based on its previous value, using (prevState) => ... is essential. This pattern ensures that your updates are dynamic and reflect the latest state, even in asynchronous or concurrent situations.
    When you want to increment or decrement a value based on its current state, like setCount((prevState) => prevState + 1) or setCount((prevState) => prevState - 1)

    TheuseEffect Hook

    useEffect is a built-in hook in React that allows you to perform side effects in function components. Side effects are operations that happen after or as a result of the main logic of your component, such as data fetching, DOM manipulation, or setting up subscriptions.
    It serves as a replacement for lifecycle methods like componentDidMount, componentDidUpdate, and componentWillUnmount in class components.

    1. When you don't provide a dependency array, the effect runs after every render. This is similar to componentDidUpdate in class components and is used for side effects that should run after each render.

    2. When you pass an empty dependency array, the effect runs only once after the initial render. This is equivalent to componentDidMount in class components and is used for one-time setup or data fetching.

    3. When you pass specific dependencies to useEffect, the effect will run whenever any of those dependencies change. This is useful for controlling when the effect should execute based on specific data changes

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

    function ExampleComponent({ data }) {
      const [count, setCount] = useState(0);

      // Effect with specific dependencies
      useEffect(() => {
        // This code runs when 'data' changes
        console.log('Data changed:', data);
      }, [data]);

      // Effect with empty dependency array (runs once)
      useEffect(() => {
        console.log('Component mounted (initial render)');
        return () => {
          console.log('Component unmounted');
        };
      }, []);

      // Effect without a dependency array (runs after every render)
      useEffect(() => {
        console.log('Component re-rendered');
      });

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

The return statement in useEffect is used to define a cleanup function that runs when the component unmounts or when the state value changes. This cleanup function is essential for tasks like clearing intervals, unsubscribing from subscriptions, or releasing resources to prevent memory leaks.

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

    function TimerComponent() {
      const [timer, setTimer] = useState(0);

      useEffect(() => {
        const intervalId = setInterval(() => {
          setTimer((prevTimer) => prevTimer + 1);
        }, 1000);

        // Cleanup function to clear the interval
        return () => {
          clearInterval(intervalId);
        };
      }, []);

      return <div>Timer: {timer} seconds</div>;
    }

In this example, the return statement is used to clear the interval created by setInterval when the component unmounts. This ensures that there are no lingering intervals that could cause memory leaks

TheuseRef Hook

useRef hook in React allows you to create and manage references to DOM elements or to persist values across renders without causing re-renders. You can directly access the dom element.

Use useRef when you need to directly manipulate DOM elements, such as focusing on an input field, measuring dimensions, or animating elements.

Don't use useRef for managing component state that affect rendering.

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

function MyComponent() {
  const inputRef = useRef();

  useEffect(() => {
    // Focus the input element when the component mounts
    inputRef.current.focus();
  }, []);

  return <input ref={inputRef} />;
}

In the next article, we will focus on more optimization hooks like useMemo, and useCallback React provides to us.