[React] useRef for preventing unnecessary re-render
When you want a component to “remember” some information, but you don’t want that information to trigger new renders, you can use a ref.
import { useRef } from 'react';
export default function Counter() {
let ref = useRef(0);
function handleClick() {
ref.current = ref.current + 1;
alert('You clicked ' + ref.current + ' times!');
}
return (
<button onClick={handleClick}>
Click me!
</button>
);
}
Note that the component doesn’t re-render with every increment. Like state, refs are retained by React between re-renders. However, setting state re-renders a component. Changing a ref does not!
When a piece of information is used for rendering, keep it in state. When a piece of information is only needed by event handlers and changing it doesn’t require a re-render, using a ref may be more efficient.
Limitations of React state don’t apply to refs. For example, state acts like a snapshot for every render and doesn’t update synchronously. But when you mutate the current value of a ref, it changes immediatel
ref.current = 5;
console.log(ref.current); // 5
This is because the ref itself is a regular JavaScript object, and so it behaves like one.
What advantages does this give us over just declaring and using a variable with let
?
import React, {useRef} from "react";
const MyFunctionalComponent = (props) => {
const refVariable = useRef('value');
//versus
let letVariable = 'value';
}
- useRef() give you the same object ref everytime; if use variable, it creates a new variable everytime.
- useRef() gives you something more permanent, like useState() but updating doesn't trigger re-render, very useful if you are doing a lot of manipulation in a chaining fashion, but wouldn't want to trigger a re-render until the end
Example:
State works like a snapshot, so you can’t read the latest state from an asynchronous operation like a timeout. However, you can keep the latest input text in a ref. A ref is mutable, so you can read the current
property at any time. Since the current text is also used for rendering, in this example, you will need both a state variable (for rendering), and a ref (to read it in the timeout). You will need to update the current ref value manually.
import { useState, useRef } from 'react';
export default function Chat() {
const [text, setText] = useState('');
const textRef = useRef(text);
function handleChange(e) {
setText(e.target.value);
textRef.current = e.target.value;
}
function handleSend() {
setTimeout(() => {
alert('Sending: ' + textRef.current);
}, 3000);
}
return (
<>
<input
value={text}
onChange={handleChange}
/>
<button
onClick={handleSend}>
Send
</button>
</>
);
}