Other Essential Hooks: useRef, useReducer, useCallback, useMemo in React JS

React provides several built-in hooks that simplify the way we work with state, side effects, and references in functional components. While useState and useEffect are the most commonly used hooks, there are other hooks like useRef, useReducer, useCallback, and useMemo that are also very powerful for managing different aspects of your React app. In this article, we will explore these essential hooks with examples.

1. useRef Hook

The useRef hook is used to create mutable object references that persist across renders. Unlike useState, updating a reference with useRef does not trigger a re-render of the component. This makes useRef perfect for storing DOM elements, timers, or any other mutable value that should persist throughout the component lifecycle.

Example of useRef

          
              import React, { useRef } from 'react';

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

                  const handleFocus = () => {
                      inputRef.current.focus();
                  };

                  return (
                      
); } export default FocusInput;

In this example, useRef is used to store a reference to the input element. When the button is clicked, the handleFocus function is triggered, and it focuses on the input field by accessing the DOM node via inputRef.current.

2. useReducer Hook

The useReducer hook is an alternative to useState for managing more complex state logic in React components. It is especially useful when the state depends on previous state values or when state updates are complex. useReducer takes a reducer function and an initial state as arguments and returns the current state and a dispatch function to update the state.

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:
                          return state;
                  }
              }

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

                  return (
                      

Count: {state.count}

); } export default Counter;

In this example, we use useReducer to manage the state of a counter. The reducer function handles different actions (like incrementing and decrementing the count), and the dispatch function is used to trigger these actions.

3. useCallback Hook

The useCallback hook returns a memoized version of a function that only changes if one of its dependencies has changed. This is useful to avoid unnecessary re-creations of functions during re-renders, which can be expensive, especially when passed down to child components as props.

Example of useCallback

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

              function ExpensiveComponent({ handleClick }) {
                  console.log('ExpensiveComponent rendered');
                  return ;
              }

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

                  const handleClick = useCallback(() => {
                      console.log('Button clicked');
                  }, []);  // Memoized function, doesn't change

                  return (
                      

Count: {count}

); } export default ParentComponent;

In this example, useCallback is used to memoize the handleClick function. Even though the ParentComponent is re-rendered when the state changes, the handleClick function is not recreated unless its dependencies change, which in this case, there are none.

4. useMemo Hook

The useMemo hook is used to memoize expensive computations so that they are only recalculated when one of their dependencies changes. This can optimize performance by preventing unnecessary recalculations of values during re-renders.

Example of useMemo

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

              function ExpensiveComputation({ num }) {
                  const computeFactorial = (n) => {
                      console.log('Computing factorial...');
                      let result = 1;
                      for (let i = 1; i <= n; i++) {
                          result *= i;
                      }
                      return result;
                  };

                  const factorial = useMemo(() => computeFactorial(num), [num]);

                  return 

Factorial of {num} is {factorial}

; } function ParentComponent() { const [num, setNum] = useState(5); return (

Current Number: {num}

); } export default ParentComponent;

In this example, useMemo is used to memoize the factorial computation. The factorial is only recomputed when the num prop changes, which helps avoid unnecessary recalculations on every render.

Conclusion

React's built-in hooks like useRef, useReducer, useCallback, and useMemo are powerful tools that can help you manage state, performance, and references more efficiently in functional components. Understanding and utilizing these hooks can lead to cleaner, more optimized React code, and ultimately, better performance in your applications. Use these hooks where appropriate, and take advantage of their capabilities to build scalable and efficient React apps.





Advertisement