What's the difference between `useRef` and `createRef`?
I was going through the hooks documentation when I stumbled upon useRef
.
Looking at their example…
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
// `current` points to the mounted text input element
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
…it seems like useRef
can be replaced with createRef
.
function TextInputWithFocusButton() {
const inputRef = createRef(); // what's the diff?
const onButtonClick = () => {
// `current` points to the mounted text input element
inputRef.current.focus();
};
return (
<>
<input ref={inputRef} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
Why do I need a hook for refs? Why does useRef
exist?
The difference is that createRef
will always create a new ref. In a class-based component, you would typically put the ref in an instance property during construction (e.g. this.input = createRef()
). You don't have this option in a function component. useRef
takes care of returning the same ref each time as on the initial rendering.
Here's an example app demonstrating the difference in the behavior of these two functions:
import React, { useRef, createRef, useState } from "react";
import ReactDOM from "react-dom";
function App() {
const [renderIndex, setRenderIndex] = useState(1);
const refFromUseRef = useRef();
const refFromCreateRef = createRef();
if (!refFromUseRef.current) {
refFromUseRef.current = renderIndex;
}
if (!refFromCreateRef.current) {
refFromCreateRef.current = renderIndex;
}
return (
<div className="App">
Current render index: {renderIndex}
<br />
First render index remembered within refFromUseRef.current:
{refFromUseRef.current}
<br />
First render index unsuccessfully remembered within
refFromCreateRef.current:
{refFromCreateRef.current}
<br />
<button onClick={() => setRenderIndex(prev => prev + 1)}>
Cause re-render
</button>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
createRef
always returns a new ref, which you'd generally store as a field on a class component's instance. useRef
returns the same ref upon every render of a functional component's instance. This is what allows the state of the ref to persist between renders, despite you not explictly storing it anywhere.
In your second example, the ref would be re-created upon every render.