useRef is just a plain javascript object
March 22, 2024 10:13 AM
I was trying to understand useRef then I read this statement on its official doc "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."
So what is it trying to convey?
In React, a ref is a way to access the properties of a component, similar to an instance variable in a class. The ref.current
property is the current value of the ref.
When it's said that "you can mutate the ref.current property", it means that you can directly change the value of ref.current
without causing a re-render of the component. This is different from state variables, where changes cause a re-render.
However, the second part of the statement warns against mutating (or changing) an object that is used for rendering. If ref.current
holds a value that is used in the render method (or function), changing it directly won't cause a re-render, and the UI won't update to reflect the changes. This can lead to inconsistencies in your UI, where the state of your application doesn't match what's being displayed.
So, while you can mutate ref.current
, you should be careful not to mutate any values that are used in rendering if you want your UI to stay consistent with your application state.
import React, { useRef } from 'react';
function TextInputWithFocusButton() {
// Initialize a ref
const inputEl = useRef(null);
const onButtonClick = () => {
// On button click, we tell the input element to focus
inputEl.current.focus();
};
return (
<>
{/* Attach the ref to the input element */}
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
export default TextInputWithFocusButton;
inputEl
is a ref. We attach it to an input element, and when the button is clicked, we use the ref to focus the input element. This is a mutation of the ref.current
property, but it's okay because it doesn't affect rendering.Another example
import React, { useRef, useEffect } from 'react';
function Counter() {
const count = useRef(0);
const increment = () => {
count.current++;
console.log(`Count: ${count.current}`);
};
return (
<div>
<p>Count: {count.current}</p>
<button onClick={increment}>Increment</button>
</div>
);
}
export default Counter;
in this above example, count
is a ref that holds the current count. When you click the "Increment" button, it increments count.current
directly. However, because count.current
is used in the render function, the UI does not update to reflect the changes. The console log will show the incremented value, but the UI will always show "Count: 0".
This is because changes ref.current
do not cause a re-render of the component. If you want changes to cause a re-render, you should use state with the useState
hook instead of a ref
Comments