React Hooks


What are React Hooks?

React Hooks are special functions introduced in React 16.8 that allow developers to use state and other React features, such as lifecycle methods, in functional components. Hooks provide a way to manage component state, side effects, context, and more without using class components.


What is the useState hook, and how is it used?

The useState hook is a React Hook that allows you to add state to functional components. It returns an array with two elements: the current state value and a function to update that state. You can initialize state by passing an initial value to useState.

Example of using useState:

import React, { useState } from 'react';

function Counter() {
    const [count, setCount] = useState(0); // Initialize state with 0

    return (
        <div>
            <p>Count: {count}</p>
            <button onClick={() => setCount(count + 1)}>Increment</button>
        </div>
    );
}

In this example, useState(0) initializes the state variable count to 0, and setCount is used to update it when the button is clicked.


What is the useEffect hook, and how does it work?

The useEffect hook allows you to perform side effects in functional components, such as data fetching, subscriptions, or manually changing the DOM. It runs after the render and can optionally clean up effects when the component unmounts or when dependencies change. The hook accepts two arguments: a callback function and an optional dependency array.

Example of using useEffect:

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

function DataFetcher() {
    const [data, setData] = useState(null);

    useEffect(() => {
        fetch('https://api.example.com/data')
            .then(response => response.json())
            .then(data => setData(data));
    }, []); // Empty array ensures the effect runs only once

    return <div>Data: {JSON.stringify(data)}</div>;
}

In this example, the effect runs once after the component is mounted to fetch data from an API, and the fetched data is stored in the component's state.


What is the dependency array in useEffect, and how does it work?

The dependency array is an optional second argument passed to useEffect that tells React when to re-run the effect. If dependencies (state or props) in the array change, the effect will run again. If the array is empty, the effect will only run once after the initial render, similar to componentDidMount() in class components.

Example with a dependency array:

useEffect(() => {
    document.title = `Count: ${count}`;
}, [count]); // The effect will run whenever `count` changes

In this example, the effect updates the document title every time the count state changes.


How do you clean up effects in useEffect?

If your effect creates side effects that need cleanup (e.g., timers, subscriptions), you can return a cleanup function from the useEffect callback. The cleanup function is called when the component unmounts or before the effect is re-run (if dependencies change).

Example of cleaning up an effect:

useEffect(() => {
    const timer = setInterval(() => {
        console.log('Tick');
    }, 1000);

    return () => clearInterval(timer); // Cleanup on unmount or before re-running
}, []); // Run once

In this example, the timer is cleared when the component unmounts, preventing memory leaks.


What is the useContext hook, and how is it used?

The useContext hook allows functional components to consume values from a React Context. Context provides a way to pass data through the component tree without manually passing props down at every level. The useContext hook makes it easy to access the context value inside a functional component.

Example of using useContext:

const ThemeContext = React.createContext('light');

function ThemeComponent() {
    const theme = useContext(ThemeContext); // Access context value

    return <div>Current theme: {theme}</div>;
}

function App() {
    return (
        <ThemeContext.Provider value="dark">
            <ThemeComponent />
        </ThemeContext.Provider>
    );
}

In this example, useContext is used to consume the theme value provided by the ThemeContext.


What is the useReducer hook, and how does it differ from useState?

useReducer is a hook that provides an alternative to useState for managing more complex state logic. It is particularly useful when the state transitions depend on multiple actions or when the state is derived from previous state values. useReducer takes a reducer function and an initial state as arguments, and it returns the current state and a dispatch function.

Example of using useReducer:

const initialState = { count: 0 };

function reducer(state, action) {
    switch (action.type) {
        case 'increment':
            return { count: state.count + 1 };
        case 'decrement':
            return { count: state.count - 1 };
        default:
            return state;
    }
}

function Counter() {
    const [state, dispatch] = useReducer(reducer, initialState);

    return (
        <div>
            <p>Count: {state.count}</p>
            <button onClick={() => dispatch({ type: 'increment' })}>Increment</button>
            <button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button>
        </div>
    );
}

In this example, useReducer manages the count state and updates it based on the dispatched actions ('increment' and 'decrement').


What is the useMemo hook, and when should you use it?

The useMemo hook is used to memoize expensive computations, ensuring that a function only runs when its dependencies change. This can help improve performance by preventing unnecessary recalculations on every render. useMemo takes a function and a dependency array as arguments.

Example of using useMemo:

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

function ExpensiveCalculation({ count }) {
    const expensiveResult = useMemo(() => {
        console.log('Calculating...');
        return count * 2;
    }, [count]);

    return <p>Result: {expensiveResult}</p>;
}

In this example, the expensive calculation is only re-run when the count value changes, thanks to useMemo.


What is the useCallback hook, and how does it optimize performance?

useCallback is a hook that memoizes a callback function, ensuring that the function reference remains the same between renders unless its dependencies change. This can optimize performance by preventing child components from re-rendering unnecessarily when the parent component re-renders.

Example of using useCallback:

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

function Child({ onClick }) {
    console.log('Child rendered');
    return <button onClick={onClick}>Click me</button>;
}

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

    const handleClick = useCallback(() => {
        console.log('Button clicked');
    }, []); // Memoize the function

    return (
        <div>
            <p>Count: {count}</p>
            <button onClick={() => setCount(count + 1)}>Increment</button>
            <Child onClick={handleClick} />
        </div>
    );
}

In this example, useCallback prevents the handleClick function from being re-created on every render, which optimizes the Child component's performance.


What is the useRef hook, and what are its common use cases?

The useRef hook provides a way to access and persist a mutable reference that doesn't trigger a re-render when it changes. It is commonly used for directly accessing DOM elements, managing focus, or holding a value that persists across renders without causing re-renders.

Example of using useRef to access a DOM element:

import React, { useRef } from 'react';

function TextInput() {
    const inputRef = useRef(null);

    const focusInput = () => {
        inputRef.current.focus(); // Directly focus the input element
    };

    return (
        <div>
            <input ref={inputRef} type="text" />
            <button onClick={focusInput}>Focus the input</button>
        </div>
    );
}

In this example, useRef is used to store a reference to the input element, and the focusInput function uses this reference to focus the input when the button is clicked.


What is the useLayoutEffect hook, and how does it differ from useEffect?

useLayoutEffect is similar to useEffect, but it fires synchronously after all DOM mutations and before the browser paints the screen. It can be used when you need to make DOM measurements or changes that should happen before the browser updates the layout, such as updating scroll positions or measuring elements.

Example of using useLayoutEffect:

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

function ScrollComponent() {
    const divRef = useRef(null);

    useLayoutEffect(() => {
        const div = divRef.current;
        div.scrollTop = div.scrollHeight; // Scroll to the bottom of the div
    });

    return <div ref={divRef} style={{ overflowY: 'scroll', height: '100px' }}>Content...</div>;
}

In this example, useLayoutEffect ensures that the scroll position is updated before the browser paints the screen, preventing any visible "jumps" in the layout.


What is the useImperativeHandle hook?

useImperativeHandle allows you to customize the instance value that is exposed to parent components when using ref. It is often used with forwardRef to control what the parent component can access via a ref, instead of exposing the entire DOM element or child component.

Example of using useImperativeHandle:

import React, { useRef, useImperativeHandle, forwardRef } from 'react';

const FancyInput = forwardRef((props, ref) => {
    const inputRef = useRef();

    useImperativeHandle(ref, () => ({
        focus: () => {
            inputRef.current.focus(); // Custom focus method
        },
    }));

    return <input ref={inputRef} type="text" />;
});

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

    return (
        <div>
            <FancyInput ref={inputRef} />
            <button onClick={() => inputRef.current.focus()}>Focus the input</button>
        </div>
    );
}

In this example, useImperativeHandle is used to expose only the focus method from the FancyInput component to the parent component via the ref.

Ads