DEV Community

Softden 2005
Softden 2005

Posted on

React Hooks: Revolutionizing Functional Components

React Hooks revolutionize how functional components manage state, lifecycle, and side effects.

Hereโ€™s a structured breakdown:

1. Basic Hooks

1.1. useState Hook

The useState hook is used to add state to functional components.

Syntax of useState:
const [state, setState] = useState(initialState);
Enter fullscreen mode Exit fullscreen mode
Example of useState:
import React, { useState } from 'react';

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

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

export default Counter;
Enter fullscreen mode Exit fullscreen mode
Behavior:
  • State Management: Provides a way to manage state in functional components.
  • Reactivity: Triggers re-renders whenever the state is updated.
Key Notes:
  • Lazy Initialization: You can pass a function to useState for lazy initialization of state.
  • Multiple States: You can use multiple useState calls to manage different state variables.

1.2. useEffect Hook

The useEffect hook allows you to perform side effects in function components.

Syntax of useEffect:
useEffect(() => {
    // effect
    return () => {
        // cleanup
    };
}, [dependencies]);
Enter fullscreen mode Exit fullscreen mode
Example of useEffect:
import React, { useEffect, useState } from 'react';

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

    useEffect(() => {
        const interval = setInterval(() => {
            setCount((c) => c + 1);
        }, 1000);

        return () => clearInterval(interval); // cleanup on unmount
    }, []);

    return <h1>{count}</h1>;
};

export default Timer;
Enter fullscreen mode Exit fullscreen mode
Behavior:
  • Side Effects: Runs side effects such as data fetching, subscriptions, or manually changing the DOM.
  • Cleanup: Cleanup functions can be returned to clean up resources.
Key Notes:
  • Dependencies: Specify dependencies to control when the effect runs.
  • Multiple Effects: You can call useEffect multiple times in a component.

2. Additional Hooks

2.1. useContext Hook

The useContext hook allows you to consume context in functional components.

Syntax of useContext:
const value = useContext(MyContext);
Enter fullscreen mode Exit fullscreen mode
Example of useContext:
import React, { useContext } from 'react';
import { MyContext } from './MyContextProvider';

const Display = () => {
    const value = useContext(MyContext);

    return <h1>{value}</h1>;
};

export default Display;
Enter fullscreen mode Exit fullscreen mode
Behavior:
  • Context Consumption: Accesses the nearest context value for the component.
  • Reactivity: The component re-renders when the context value changes.
Key Notes:
  • Context Provider: Ensure your component is wrapped in the relevant context provider.
  • Performance Optimization: Use memoization techniques for performance in large applications.

3. Redux Hooks

3.1. useSelector Hook

The useSelector hook allows you to extract data from the Redux store state.

Syntax of useSelector:
const selectedState = useSelector(selector);
Enter fullscreen mode Exit fullscreen mode
Example of useSelector:
import React from 'react';
import { useSelector } from 'react-redux';

const CounterDisplay = () => {
    const count = useSelector((state) => state.counter.value);

    return <h1>{count}</h1>;
};

export default CounterDisplay;
Enter fullscreen mode Exit fullscreen mode
Behavior:
  • State Selection: Automatically re-renders the component when the selected state changes.
  • Memoization: Uses === equality check to prevent unnecessary re-renders.
Key Notes:
  • Selector Function: The selector function can be a simple function that returns a piece of the state.
  • Performance Optimization: For better performance, you can use libraries like reselect.

3.2. useDispatch Hook

The useDispatch hook gives you access to the dispatch function from the Redux store.

Syntax of useDispatch:
const dispatch = useDispatch();
Enter fullscreen mode Exit fullscreen mode
Example of useDispatch:
import React from 'react';
import { useDispatch } from 'react-redux';
import { increment } from './counterSlice';

const CounterButton = () => {
    const dispatch = useDispatch();

    const handleIncrement = () => {
        dispatch(increment());
    };

    return <button onClick={handleIncrement}>Increment</button>;
};

export default CounterButton;
Enter fullscreen mode Exit fullscreen mode
Behavior:
  • Dispatch Actions: Allows you to dispatch actions to update the Redux store.
  • Function Component: Designed to be used in function components.
Key Notes:
  • Action Creators: You can dispatch action creators directly or use strings to create actions dynamically.
  • Asynchronous Actions: Consider using middleware like redux-thunk or redux-saga.

3.3. useStore Hook

The useStore hook provides access to the Redux store directly.

Syntax of useStore:
const store = useStore();
Enter fullscreen mode Exit fullscreen mode
Example of useStore:
import React from 'react';
import { useStore } from 'react-redux';

const StoreDisplay = () => {
    const store = useStore();
    const state = store.getState();

    return <pre>{JSON.stringify(state, null, 2)}</pre>;
};

export default StoreDisplay;
Enter fullscreen mode Exit fullscreen mode
Behavior:
  • Direct Access: Allows direct access to the store instance for more advanced usage.
  • State Reading: Read the entire state of the Redux store using store.getState().
Key Notes:
  • Not Recommended for Most Cases: Generally not recommended; useSelector is preferred.
  • Manual Subscriptions: You can manually subscribe to the store.

4. Custom Hooks

Custom hooks allow you to encapsulate reusable logic.

4.1. useFetch Hook

A custom hook to fetch data from an API.

Syntax of useFetch:
const { data, loading, error } = useFetch(url);
Enter fullscreen mode Exit fullscreen mode
Example of useFetch:
import { useState, useEffect } from 'react';

const useFetch = (url) => {
    const [data, setData] = useState(null);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(null);

    useEffect(() => {
        const fetchData = async () => {
            try {
                const response = await fetch(url);
                const result = await response.json();
                setData(result);
            } catch (err) {
                setError(err);
            } finally {
                setLoading(false);
            }
        };

        fetchData();
    }, [url]);

    return { data, loading, error };
};

export default useFetch;
Enter fullscreen mode Exit fullscreen mode
Behavior:
  • Data Fetching: Manages the fetch process, including loading and error states.
  • Reactivity: Automatically re-fetches when the URL changes.
Key Notes:
  • Error Handling: Ensure to handle errors gracefully for a better user experience.
  • Reusability: Encapsulates the fetching logic for use across multiple components.

5. React Router Hooks

5.1. useHistory Hook

The useHistory hook allows you to access the history instance.

Syntax of useHistory:
const history = useHistory();
Enter fullscreen mode Exit fullscreen mode
Example of useHistory:
import React from 'react';
import { useHistory } from 'react-router-dom';

const HomeButton = () => {
    const history = useHistory();

    const handleClick = () => {
        history.push('/home');
    };

    return <button onClick={handleClick}>Go to Home</button>;
};

export default HomeButton;
Enter fullscreen mode Exit fullscreen mode
Behavior:
  • Navigation: Allows you to navigate programmatically within your application.
  • History Management: Provides access to the history instance for managing browser history.
Key Notes:
  • Integration with React Router: Make sure your component is within a <Router> to access history.
  • Use Cases: Useful for navigating after form submissions or button clicks.

5.2. useParams Hook

The useParams hook lets you access URL parameters.

Syntax of useParams:
const { paramName } = useParams();
Enter fullscreen mode Exit fullscreen mode
Example of useParams:
import React from 'react';
import { useParams } from 'react-router-dom';

const UserProfile = () => {
    const { userId } = useParams();

    return <h1>User ID: {userId}</h1>;
};

export default UserProfile;
Enter fullscreen mode Exit fullscreen mode
Behavior:
  • URL Parameters: Extracts parameters from the current URL, making it easy to use dynamic routes.
  • Reactivity: Automatically re-renders the component when parameters change.
Key Notes:
  • Parameter Types: Make sure to validate and handle parameter types correctly in your application.
  • Usage in Nested Routes: Can be used in nested routing scenarios to access parent route parameters.

6. Advanced Hooks

6.1

. useReducer Hook

The useReducer hook is an alternative to useState for managing complex state logic.

Syntax of useReducer:
const [state, dispatch] = useReducer(reducer, initialState);
Enter fullscreen mode Exit fullscreen mode
Example of useReducer:
import React, { useReducer } from 'react';

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:
            throw new Error();
    }
}

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

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

export default Counter;
Enter fullscreen mode Exit fullscreen mode
Behavior:
  • Complex State Management: Allows for managing more complex state objects compared to useState.
  • Reducer Function: Utilizes a reducer function to define how state updates occur.
Key Notes:
  • Dispatching Actions: Similar to Redux, you dispatch actions to update the state.
  • Separation of Concerns: Encourages separation of state logic, making components cleaner.

6.2. useMemo Hook

The useMemo hook memoizes expensive calculations, improving performance.

Syntax of useMemo:
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
Enter fullscreen mode Exit fullscreen mode
Example of useMemo:
import React, { useMemo } from 'react';

const ExpensiveComponent = ({ a, b }) => {
    const computedValue = useMemo(() => {
        // Simulating an expensive calculation
        return a + b;
    }, [a, b]);

    return <h1>{computedValue}</h1>;
};

export default ExpensiveComponent;
Enter fullscreen mode Exit fullscreen mode
Behavior:
  • Performance Optimization: Avoids recalculating values on every render unless dependencies change.
  • Memoization: Stores the computed value in memory for the lifetime of the component.
Key Notes:
  • Use Cases: Ideal for optimizing performance in components with expensive calculations.
  • Not a Replacement for useEffect: Does not perform side effects; use useEffect for that purpose.

6.3. useCallback Hook

The useCallback hook returns a memoized callback function, useful for optimizing performance.

Syntax of useCallback:
const memoizedCallback = useCallback(() => {
    // function logic
}, [dependencies]);
Enter fullscreen mode Exit fullscreen mode
Example of useCallback:
import React, { useState, useCallback } from 'react';

const Button = React.memo(({ onClick, children }) => {
    console.log('Button rendered');
    return <button onClick={onClick}>{children}</button>;
});

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

    const handleClick = useCallback(() => {
        setCount((c) => c + 1);
    }, []);

    return (
        <>
            <h1>{count}</h1>
            <Button onClick={handleClick}>Increment</Button>
        </>
    );
};

export default ParentComponent;
Enter fullscreen mode Exit fullscreen mode
Behavior:
  • Callback Memoization: Returns a memoized version of the callback that only changes if dependencies change.
  • Component Performance: Helps prevent unnecessary renders of child components that depend on the callback.
Key Notes:
  • Use with Memoized Components: Often used with React.memo for optimized rendering.
  • Avoid Overuse: Only use when necessary, as overuse can lead to unnecessary complexity.

Summary of Key Takeaways

  • Basic Hooks (e.g., useState, useEffect) provide fundamental state management and side effect handling.
  • Additional Hooks (e.g., useContext) facilitate consuming context effectively.
  • Redux Hooks (useSelector, useDispatch, useStore) simplify state management with Redux.
  • Custom Hooks allow for encapsulation of reusable logic, like data fetching.
  • React Router Hooks (useHistory, useParams) aid in navigating and accessing URL parameters.
  • Advanced Hooks (e.g., useReducer, useMemo, useCallback) enhance performance and manage complex state logic.

Top comments (0)