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.