React
RE06

RE06 Exercises

Practical Exercises

  1. Using useCallback

Objective: Optimize a component with useCallback to prevent unnecessary re-renders.

Task:

Create a component List that renders items from a prop items. Include a button that toggles the sorting of the items. Use useCallback to ensure the sorting function does not cause unnecessary re-renders.

import React, { useState, useCallback } from 'react';
 
const List = ({ items }) => {
    const [isSorted, setIsSorted] = useState(false);
 
    const sortItems = useCallback(() => {
        if (isSorted) {
            return [...items].sort();
        }
        return items;
    }, [items, isSorted]);
 
    return (
        <>
            <button onClick={() => setIsSorted(!isSorted)}>Toggle Sort</button>
            {sortItems().map((item, index) => <div key={index}>{item}</div>)}
        </>
    );
};
  1. Using useMemo

Objective: Implement useMemo to optimize expensive calculations.

Task:

Create a component that calculates and displays the factorial of a number. Use useMemo to cache the factorial calculation.

import React, { useState, useMemo } from 'react';
 
const factorial = (n) => {
    let result = 1;
    for (let i = 2; i <= n; i++) {
        result *= i;
    }
    return result;
};
 
const FactorialCalculator = () => {
    const [number, setNumber] = useState(1);
    const factorialOfNumber = useMemo(() => factorial(number), [number]);
 
    return (
        <div>
            <input type="number" value={number} onChange={e => setNumber(Number(e.target.value))} />
            <p>Factorial: {factorialOfNumber}</p>
        </div>
    );
};
  1. Writing a Custom Hook

Objective: Write a custom hook to manage form inputs.

Task:

Create a custom hook useFormInput that manages the state of a form input. Use this hook in a component to create a controlled input.

import React, { useState } from 'react';
 
const useFormInput = (initialValue) => {
    const [value, setValue] = useState(initialValue);
 
    const handleChange = (e) => {
        setValue(e.target.value);
    };
 
    return {
        value,
        onChange: handleChange
    };
};
 
const FormComponent = () => {
    const name = useFormInput('');
 
    return (
        <form>
            <input type="text" {...name} />
            <p>Your name is {name.value}</p>
        </form>
    );
};
  1. Write a custom hook useOutsideClick that detects clicks outside of a given element and executes a callback function when such clicks occur.

Task:

Create a custom hook useOutsideClick that returns a ref and a callback function. The hook should add an event listener to the document that checks if the click target is outside the referenced element. If a click occurs outside the referenced element, the hook should call the provided callback function. Ensure the hook cleans up the event listener to prevent memory leaks.

import React, { useEffect, useRef } from 'react';
 
function useOutsideClick<E extends HTMLElement>(callback: () => void) {
    const ref = useRef<E>(null);
 
    useEffect(() => {
        const handleClickOutside = (event: MouseEvent) => {
            if (ref.current && !ref.current.contains(event.target as Node)) {
                callback();
            }
        };
 
        document.addEventListener("mousedown", handleClickOutside);
        return () => {
            document.removeEventListener("mousedown", handleClickOutside);
        };
    }, [callback]);
 
    return ref;
};
 
const OutsideClickExample: React.FC = () => {
    const handleOutsideClick = () => console.log("Clicked outside of the element");
    const outsideClickRef = useOutsideClick<HTMLDivElement>(handleOutsideClick);
 
    return (<div ref={outsideClickRef} style={{ border: "1px solid black", padding: "20px" }}>
             Click outside of this box
        </div>);
};
 
export default OutsideClickExample;