UseRef vs useState in React: Key Differences and When to Use Each
useState is for managing state that triggers UI updates when changed, while useRef holds mutable values that persist across renders without causing re-renders.Quick Comparison
Here is a quick side-by-side comparison of useRef and useState in React.
| Factor | useState | useRef |
|---|---|---|
| Purpose | Stores state that triggers UI updates | Stores mutable values without triggering UI updates |
| Triggers re-render? | Yes, on state change | No, value changes do not cause re-render |
| Initial value | Passed as argument to useState | Passed as argument to useRef |
| Common use cases | UI state like form inputs, toggles | Accessing DOM elements, storing timers or mutable variables |
| Value persistence | Persists across renders | Persists across renders |
| Setter function | Yes, to update state | No setter, value changed directly on .current |
Key Differences
useState is designed to hold data that affects what the user sees on the screen. When you update state with useState, React re-renders the component to reflect the new state. This makes it perfect for things like toggling visibility, updating text, or tracking user input.
On the other hand, useRef holds a mutable object with a current property that you can change without causing a re-render. This is useful when you want to keep track of values that don't need to update the UI, such as timers, previous values, or references to DOM elements.
In summary, use useState when changes should update the UI, and use useRef when you want to keep data around without triggering a render.
Code Comparison
This example shows how to count button clicks using useState. The count updates on the screen each time the button is clicked.
import React, { useState } from 'react'; export default function ClickCounter() { const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}>Click me</button> </div> ); }
useRef Equivalent
This example uses useRef to keep track of clicks without causing the component to re-render. The count updates internally but the UI does not change.
import React, { useRef } from 'react'; export default function ClickCounterRef() { const countRef = useRef(0); function handleClick() { countRef.current += 1; console.log(`Clicked ${countRef.current} times`); } return ( <div> <p>Click the button and check the console</p> <button onClick={handleClick}>Click me</button> </div> ); }
When to Use Which
Choose useState when: you want React to update the UI based on changes, such as showing new text, toggling elements, or updating form inputs.
Choose useRef when: you need to keep track of values that do not affect rendering, like timers, previous values, or direct DOM references.
Using the right hook helps keep your app efficient and your code clear.
Key Takeaways
useState triggers UI updates when its value changes.useRef holds mutable values without causing re-renders.useState for data that affects what the user sees.useRef for storing values that don’t need to update the UI.