As an intermediate React developer, you’re probably already familiar with the useState
hook for managing component state. However, you might be wondering when and why you should use the useRef
hook in addition to useState
. In this blog post, we’ll explore a practical example of using useRef
and useState
together to track the render count of a React component. By the end, you’ll have a better understanding of why useRef
is essential for certain scenarios, and how it can complement useState
in managing component behavior.
We want to track the number of times a component has been rendered without causing additional re-renders. We also want to manage multiple state values that control different aspects of the component.
To achieve this, we’ll create a custom React hook that uses useRef
to store the render count and useState
to manage different state values within the component.
The useRef
hook is used for storing mutable values across renders without causing re-renders when its value changes. This makes it an ideal candidate for tracking render count without causing an infinite loop of re-renders, which would happen if we were to use useState
for this purpose.
Let’s create a custom hook called useComponentRenderCount
that uses useRef
to store the render count and increments it on every render using the useEffect
hook.
import { useRef, useEffect } from 'react';
function useComponentRenderCount() {
const renderCountRef = useRef(0);
useEffect(() => {
renderCountRef.current = renderCountRef.current + 1;
});
return renderCountRef.current;
}
Now let’s use this custom hook in a component that has two separate state values, one for a timer and one for click events.
import React, { useState, useEffect } from 'react';
import useComponentRenderCount from './useComponentRenderCount';
function App() {
const renderCount = useComponentRenderCount();
const [timerCount, setTimerCount] = useState(0);
const [clickCount, setClickCount] = useState(0);
useEffect(() => {
const timer = setInterval(() => {
setTimerCount((prevCount) => prevCount + 1);
}, 1000);
return () => {
clearInterval(timer);
};
}, []);
const handleClick = () => {
setClickCount((prevCount) => prevCount + 1);
};
return (
<div>
<p>Component render count: {renderCount}</p>
<p>Timer count: {timerCount}</p>
<p>Click count: {clickCount}</p>
<button onClick={handleClick}>Increment click count</button>
</div>
);
}
export default App;
In this example, we have two state values, timerCount
and clickCount
. By separating these state values, we can control different aspects of the component independently. This improves code readability and makes it easier to manage state updates for each value. In our example, the timer state is updated every second using setInterval
, and the click state is updated when the button is clicked.
Understanding when to use useRef
in addition to useState
is crucial for managing complex component behavior in React. In this example, we used useRef
to track the render count without causing additional re-renders, and useState
to manage multiple state values independently. This allowed us to update different aspects of the component while keeping the render count tracking efficient and performant.
As you continue to develop your React skills, always consider the different use cases for hooks like useRef
and useState
. Balancing performance and functionality is key to creating high-quality applications. Happy coding!