useRef
Mental model:
- think of it as a state, but unlike state, ref does not trigger a re-render of the component
- you can make updates to the ref and read that value without a re-render
- hence ref values are used for values that are not needed for rendering (not if you want to update a value in a component)
- refs are also useful for manipulating HTML DOM elements
Calling useRef
Call useRef at the top level of your component to declare a ref.
import { useRef } from 'react';
function MyComponent() {
const intervalRef = useRef(0);
const inputRef = useRef(null);
useRef
vs useState
useState
triggers a new re-render, and the updated value of that state is only reflected after the re-renderuseRef
does not trigger a re-render, and the updated value of that ref is reflected immediately
export default function Example() {
const [count, setCount] = useState(0);
const countRef = useRef(0);
const handleIncrement = () => {
setCount(count + 1);
countRef.current++;
console.log("State:", count); // 0
console.log("Ref:", countRef.current); // 1
};
// if you use countRef.current in the return statement, it will always be 0
// unless the component is re-rendered by other means
return (
<div>
Count: {count}
<button onClick={handleIncrement}>Increment</button>
</div>
);
}
When to use useRef
- when you want to store a value that is not needed for rendering
- manipulating HTML DOM elements
export function Example() {
const inputRef = (useRef < HTMLInputElement) | (null > null);
useEffect(() => {
inputRef.current?.focus();
}, []);
return (
<div className="tutorial">
<input ref={inputRef} type="text" placeholder="Type something..." />
</div>
);
}
Caveats
You can mutate the ref.current
property. Unlike state, it is mutable. However, if it holds an object that is used for rendering (for example, a piece of your state), then you shouldn’t mutate that object.
When you change the ref.current
property, React does not re-render your component. React is not aware of when you change it because a ref is a plain JavaScript object.
Do not write or read ref.current
during rendering, except for initialization. This makes your component’s behavior unpredictable.
In Strict Mode, React will call your component function twice in order to help you find accidental impurities. This is development-only behavior and does not affect production. Each ref object will be created twice, but one of the versions will be discarded. If your component function is pure (as it should be), this should not affect the behavior.