admin管理员组文章数量:1129221
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?
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?
6 Answers
Reset to default 313The 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);
tldr
A ref
is a plain JS object { current: <some value> }
.
React.createRef()
is a factory returning a ref { current: null }
- no magic involved.
useRef(initValue)
also returns a ref { current: initValue }
akin to React.createRef()
. Besides, it memoizes this ref to be persistent across multiple renders in a function component.
It is sufficient to use React.createRef
in class components, as the ref object is assigned to an instance variable, hence accessible throughout the component and its lifecyle:
this.myRef = React.createRef(); // stores ref in "mutable" this context (class)
useRef(null)
basically is equivalent to useState(React.createRef())[0]
1.
1 Replace useRef
with useState
+ createRef
Following tweet has been enlightening for me:
useRef()
is basicallyuseState({current: initialValue })[0]
.
With insights from the tldr
section, we now can further conclude:
useRef(null)
is basicallyuseState(React.createRef())[0]
.
Above code "abuses" useState
to persist the returned ref from React.createRef()
. [0]
just selects the value part of useState
- [1]
would be the setter.
useState
causes a re-render in contrast to useRef
. More formally, React compares the old and new object reference for useState
, when a new value is set via its setter method. If we mutate the state of useState
directly (opposed to setter invocation), its behavior more or less becomes equivalent to useRef
, as no re-render is triggered anymore:
// Example of mutating object contained in useState directly
const [ref] = useState({ current: null })
ref.current = 42; // doesn't cause re-render
Note: Don't do this! Use the optimized useRef
API instead of reinventing the wheel. Above is for illustration purposes.
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.
Just to highlight a purpose:
createRef
is as simple as return {current: null}
. It's a way to handle ref=
prop in most modern way and that's it(while string-based is toooo way magic and callback-based looks too verboose).
useRef
keeps some data before renders and changing it does not cause re-render(as useState
does). They are rarely related. Everything you expect for class-based component go to instance fields(this.* =
) looks like candidate to be implemented with useRef
in functional components.
Say useCallback
works as bounded class methods(this.handleClick = .....bind(this)
) and may be re-implemented(but we should not re-invent the wheel for sure) with useRef
.
Another examples are DOM refs, timeout/interval IDs, any 3rd party libraries' identifiers or references.
PS I believe React team better chose different naming for useRef
to avoid confusion with createRef
. Maybe useAndKeep
or even usePermanent
.
A ref is a plain JS object { current: }.
React.useRef(initValue) return a ref { current: initValue }
it is remember ref value across multiple render of function component.
It is advise to use in Function component
React.createRef(initValue) also return a ref { current: initValue }
it is not remember ref value across multiple render of function components. It is advise to use in class based component
useRef and forwardRef are two different things in React with different use cases.
import React, { useRef } from 'react';
const App = () => {
const inputRef = useRef(null);
const handleClick = () => {
inputRef.current.focus();
};
return (
<div>
<input type="text" ref={inputRef} />
<button onClick={handleClick}>Focus input</button>
</div>
);
};
export default App;
And on the other hand:
import React, { forwardRef } from 'react';
const CustomInput = forwardRef((props, ref) => {
return (
<input type="text" ref={ref} />
);
});
const App = () => {
const inputRef = React.createRef();
const handleClick = () => {
inputRef.current.focus();
};
return (
<div>
<CustomInput ref={inputRef} />
<button onClick={handleClick}>Focus
</div>
)
本文标签: javascriptWhat39s the difference between useRef and createRefStack Overflow
版权声明:本文标题:javascript - What's the difference between `useRef` and `createRef`? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736739185a1950414.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论