Refs
offer a way to access DOM
nodes or React
elements created in the render
method.
In a typical React
data flow, props
are the only way for a parent component to interact with a child component. To modify a child component, you need to re-render it with new props
. However, in some cases, you may need to forcefully modify a child component outside of the typical data flow. The modified child component could be an instance of a React
component or a DOM
element, and React
provides solutions for both of these scenarios.
Avoid using refs
to perform anything that can be achieved declaratively. Typically, do not rely on refs
when props
and state
can be used. However, there are several scenarios where using refs
is appropriate:
- Managing focus, text selection, or media playback.
- Triggering imperative animations.
- Integrating third-party
DOM
libraries.
The ref
property provided by React
represents a reference to the actual instance of the component returned by ReactDOM.render()
. It is important to differentiate between rendering a component and rendering a native DOM
element. When rendering a component, the returned value is the component instance, while rendering a DOM
element returns a specific DOM
node. React
provides three ways to use ref
.
The ref
can be directly set as a string value, but this approach is not recommended and may not be supported in future versions of React
. This is mainly due to some issues caused by using strings. For example, when ref
is defined as a string, React
needs to track the currently rendering component. During the reconciliation phase, the process of creating and updating React Element
, the ref
will be encapsulated as a closure function and will be executed during the commit phase. This may have some impact on React
performance.
class InputOne extends React.Component {
componentDidMount() {
this.refs.inputRef.value = 1;
}
render() {
return <input ref="inputRef" />;
}
}
React
allows adding a special property to any component, and the ref
property accepts a callback function that is executed immediately when the component is loaded or unloaded.
- When adding the
ref
property to anHTML
element, theref
callback receives the underlyingDOM
element as a parameter. - When adding the
ref
property to a component, theref
callback receives the current component instance as a parameter. - When the component is unmounted,
null
is passed in. - The
ref
callback is executed before lifecycle callbacks such ascomponentDidMount
orcomponentDidUpdate
.
We often use Callback Ref
in the form of an inline function, which is re-created on every render. Since React
cleans up the old ref
and sets a new one, it will be called twice during the update, first with null
. If there is business logic in the Callback
, it may cause errors. This can be avoided by defining the Callback
as a class member function and then binding it.
class InputTwo extends React.Component {
componentDidMount() {
this.inputRef.value = 2;
}
render() {
return <input ref={(element) => this.inputRef = element} />;
}
}
In React v16.3
, the new React.createRef
API was introduced through the 0017-new-create-ref
proposal. When the ref
is passed to an element in the render
, a reference to that node can be accessed in the ref
's current
property. The value of the ref
differs based on the type of node:
- When the
ref
property is used for anHTML
element, theref
created usingReact.createRef()
in the constructor receives the underlyingDOM
element as itscurrent
property. - When the
ref
property is used for a customclass
component, theref
object receives the mounting instance of the component as itscurrent
property. - The
ref
property cannot be used on function components because they do not have instances.
Comparing CreateRef
with Callback Ref
, there is no overwhelming advantage; it is just meant to be a convenient feature. There may be a slight performance advantage with CreateRef
as Callback Ref
adopts the pattern of allocating ref
in the closure function during the component render process, while CreateRef
adopts the Object Ref
.
class InputThree extends React.Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
}
componentDidMount() {
this.inputRef.current.value = 3;
}
render() {
return <input ref={this.inputRef} />;
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React</title>
</head>
<body>
<div id="root"></div>
</body>
<script src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
class InputOne extends React.Component {
componentDidMount() {
this.refs.inputRef.value = 1;
}
render() {
return <input ref="inputRef" />;
}
}
class InputTwo extends React.Component {
componentDidMount() {
this.inputRef.value = 2;
}
render() {
return <input ref={(element) =>this.inputRef = element} />;
}
}
class InputThree extends React.Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
}
componentDidMount() {
this.inputRef.current.value = 3;
}
render() {
return <input ref={this.inputRef} />;
}
}
var vm = ReactDOM.render(
<>
<InputOne />
<InputTwo />
<InputThree />
</>,
document.getElementById("root")
);
</script>
</html>
https://github.com/WindrunnerMax/EveryDay
https://zhuanlan.zhihu.com/p/40462264
https://www.jianshu.com/p/4e2357ea1ba1
https://juejin.cn/post/6844903809274085389
https://juejin.cn/post/6844904048882106375
https://segmentfault.com/a/1190000008665915
https://zh-hans.reactjs.org/docs/refs-and-the-dom.html