How to Use useRef to Avoid Re-renders in React
Use
useRef to hold a mutable value that persists across renders without triggering re-renders when updated. Unlike useState, updating a useRef value does not cause the component to re-render, making it ideal for storing values like timers or previous state references.Syntax
The useRef hook returns a mutable object with a current property. You can read or write to ref.current without causing the component to re-render.
Basic syntax:
const ref = useRef(initialValue);- creates a ref object.ref.current- holds the mutable value.
javascript
import { useRef } from 'react'; function MyComponent() { const myRef = useRef(0); // initial value is 0 // Access or update myRef.current without re-render return null; }
Example
This example shows a counter that updates a useRef value without re-rendering the component. The displayed count stays the same, but the ref value changes internally.
javascript
import React, { useRef, useState } from 'react'; function Counter() { const countRef = useRef(0); const [ignored, setIgnored] = useState(0); // to force re-render manually function incrementRef() { countRef.current += 1; // update ref without re-render console.log('Ref count:', countRef.current); } function forceRender() { setIgnored(i => i + 1); // force re-render to see updated ref } return ( <div> <p>Displayed count (state): {ignored}</p> <button onClick={incrementRef}>Increment Ref (no re-render)</button> <button onClick={forceRender}>Force Re-render</button> <p>Check console to see ref value updates.</p> </div> ); } export default Counter;
Output
Displayed count (state): 0
[Clicking 'Increment Ref' updates ref.current but UI does not change]
[Clicking 'Force Re-render' updates displayed count to show latest state]
Common Pitfalls
Updating useRef does not trigger re-renders. If you expect the UI to update when changing ref.current, it won't happen automatically.
Wrong: Trying to display ref.current directly without state will not update UI.
Right: Use useState to trigger re-renders when UI must update, and useRef for mutable values that don't affect rendering.
javascript
import React, { useRef } from 'react'; function WrongExample() { const countRef = useRef(0); function increment() { countRef.current += 1; } return ( <div> <p>Count: {countRef.current}</p> {/* This won't update on increment */} <button onClick={increment}>Increment</button> </div> ); } // Correct way uses useState to update UI import React, { useRef, useState } from 'react'; function RightExample() { const countRef = useRef(0); const [count, setCount] = useState(0); function increment() { countRef.current += 1; setCount(countRef.current); // triggers re-render } return ( <div> <p>Count: {count}</p> <button onClick={increment}>Increment</button> </div> ); }
Quick Reference
- useRef(initialValue): creates a ref object with
currentproperty. - ref.current: mutable value that does not cause re-render on change.
- Use
useReffor storing values like timers, previous props, or mutable variables. - Use
useStatewhen UI must update on value change.
Key Takeaways
useRef stores mutable values that persist without causing re-renders.
Updating ref.current does not update the UI automatically.
Use useState to trigger UI updates when needed.
useRef is ideal for storing timers, DOM references, or previous values.
Avoid expecting useRef changes to cause component re-renders.