I’m trying to understand how the React ref works when using it to manipulate DOM. I’m borrowing a modified version of the first example on the React’s website (v18.3.1) -> Learn as an example:
In the following two code, the first throws an error, but the second works fine. What is happening under-the-hood?
1.
import { useRef } from 'react';
export default function Form() {
const inputRef = useRef(null);
inputRef.current = 2; // the only difference
function handleClick() {
inputRef.current.focus();
}
return (
<>
<input ref={inputRef} />
<button onClick={handleClick}>
Focus the input
</button>
</>
);
}
gives Runtime Error
App.js: inputRef.current.focus is not a function (8:21)
2.
import { useRef } from 'react';
export default function Form() {
const inputRef = useRef(null);
inputRef.current = null; // the only difference
function handleClick() {
inputRef.current.focus();
}
return (
<>
<input ref={inputRef} />
<button onClick={handleClick}>
Focus the input
</button>
</>
);
}
I’m interpreting that during every React update, the inputRef.current
will get reassigned according to React
React sets
ref.current
during the commit. Before updating the DOM, React sets the affectedref.current
values tonull
. After updating the DOM, React immediately sets them to the corresponding DOM nodes.
Then shouldn’t anything I’ve done to inputRef.current
be ignored and overwritten by <input ref={inputRef} />
? Why does it throw an error if I had set inputRef.current
to 2?
Another example of reassigning the inputRef:
import { useRef, useState } from 'react';
export default function Form() {
const inputRef = useRef(null);
const inputRef2 = useRef(null);
const [state, setState] = useState(1);
function handleClick() {
inputRef.current.focus();
inputRef.current = inputRef2.current;
setState(state+1); // just to trigger re-render
}
return (
<>
{state}
<input ref={inputRef} /> // does this reset inputRef everytime it re-renders?
<input ref={inputRef2} />
<button onClick={handleClick}>
Focus the input
</button>
</>
);
}
In this case, the first click will focus on the first input box, and the second click will focus on the second input box. I don’t understand how did that happen. what exactly does the line <input ref={inputRef} />
do during every re-render?