findDOMNode
为 React 类组件 实例找到浏览器 DOM 节点。
¥findDOMNode
finds the browser DOM node for a React class component instance.
const domNode = findDOMNode(componentInstance)
参考
¥Reference
findDOMNode(componentInstance)
调用 findDOMNode
以查找给定 React 类组件 实例的浏览器 DOM 节点。
¥Call findDOMNode
to find the browser DOM node for a given React class component instance.
import { findDOMNode } from 'react-dom';
const domNode = findDOMNode(componentInstance);
参数
¥Parameters
-
componentInstance
:Component
子类的实例。例如,类组件中的this
。¥
componentInstance
: An instance of theComponent
subclass. For example,this
inside a class component.
返回
¥Returns
findDOMNode
返回给定 componentInstance
中第一个最近的浏览器 DOM 节点。当一个组件渲染到 null
,或者渲染 false
,findDOMNode
返回 null
。当组件渲染为字符串时,findDOMNode
返回包含该值的文本 DOM 节点。
¥findDOMNode
returns the first closest browser DOM node within the given componentInstance
. When a component renders to null
, or renders false
, findDOMNode
returns null
. When a component renders to a string, findDOMNode
returns a text DOM node containing that value.
注意事项
¥Caveats
-
组件可能会返回一个数组或一个具有多个子项的 分段。在这种情况下,
findDOMNode
将返回对应于第一个非空子节点的 DOM 节点。¥A component may return an array or a Fragment with multiple children. In that case
findDOMNode
, will return the DOM node corresponding to the first non-empty child. -
findDOMNode
仅适用于已挂载的组件(即已放置在 DOM 中的组件)。如果你试图在一个还没有挂载的组件上调用它(比如在一个还没有创建的组件上调用findDOMNode()
inrender()
),将会抛出异常。¥
findDOMNode
only works on mounted components (that is, components that have been placed in the DOM). If you try to call this on a component that has not been mounted yet (like callingfindDOMNode()
inrender()
on a component that has yet to be created), an exception will be thrown. -
findDOMNode
仅返回你调用时的结果。如果子组件稍后渲染不同的节点,则无法通知你此更改。¥
findDOMNode
only returns the result at the time of your call. If a child component renders a different node later, there is no way for you to be notified of this change. -
findDOMNode
接受类组件实例,因此不能与函数组件一起使用。¥
findDOMNode
accepts a class component instance, so it can’t be used with function components.
用法
¥Usage
查找类组件的根 DOM 节点
¥Finding the root DOM node of a class component
使用 类组件 实例(通常为 this
)调用 findDOMNode
以查找它已渲染的 DOM 节点。
¥Call findDOMNode
with a class component instance (usually, this
) to find the DOM node it has rendered.
class AutoselectingInput extends Component {
componentDidMount() {
const input = findDOMNode(this);
input.select()
}
render() {
return <input defaultValue="Hello" />
}
}
此处,input
变量将设置为 <input>
DOM 元素。这让你可以用它做一些事情。比如点击下方 “显示示例” 挂载输入时,input.select()
选择输入中的所有文本:
¥Here, the input
variable will be set to the <input>
DOM element. This lets you do something with it. For example, when clicking “Show example” below mounts the input, input.select()
selects all text in the input:
import { Component } from 'react'; import { findDOMNode } from 'react-dom'; class AutoselectingInput extends Component { componentDidMount() { const input = findDOMNode(this); input.select() } render() { return <input defaultValue="Hello" /> } } export default AutoselectingInput;
备选方案
¥Alternatives
从引用读取组件自己的 DOM 节点
¥Reading component’s own DOM node from a ref
使用 findDOMNode
的代码很脆弱,因为 JSX 节点和操作相应 DOM 节点的代码之间的连接并不明确。例如,尝试将此 <input />
封装成 <div>
:
¥Code using findDOMNode
is fragile because the connection between the JSX node and the code manipulating the corresponding DOM node is not explicit. For example, try wrapping this <input />
into a <div>
:
import { Component } from 'react'; import { findDOMNode } from 'react-dom'; class AutoselectingInput extends Component { componentDidMount() { const input = findDOMNode(this); input.select() } render() { return <input defaultValue="Hello" /> } } export default AutoselectingInput;
这会破坏代码,因为现在,findDOMNode(this)
找到了 <div>
DOM 节点,但代码需要 <input>
DOM 节点。为避免此类问题,请使用 createRef
来管理特定的 DOM 节点。
¥This will break the code because now, findDOMNode(this)
finds the <div>
DOM node, but the code expects an <input>
DOM node. To avoid these kinds of problems, use createRef
to manage a specific DOM node.
在此示例中,不再使用 findDOMNode
。而是,inputRef = createRef(null)
被定义为类的实例字段。要从中读取 DOM 节点,可以使用 this.inputRef.current
。要将它附加到 JSX,你需要渲染 <input ref={this.inputRef} />
。这将使用 DOM 节点的代码连接到它的 JSX:
¥In this example, findDOMNode
is no longer used. Instead, inputRef = createRef(null)
is defined as an instance field on the class. To read the DOM node from it, you can use this.inputRef.current
. To attach it to the JSX, you render <input ref={this.inputRef} />
. This connects the code using the DOM node to its JSX:
import { createRef, Component } from 'react'; class AutoselectingInput extends Component { inputRef = createRef(null); componentDidMount() { const input = this.inputRef.current; input.select() } render() { return ( <input ref={this.inputRef} defaultValue="Hello" /> ); } } export default AutoselectingInput;
在没有类组件的现代 React 中,等效代码会调用 useRef
:
¥In modern React without class components, the equivalent code would call useRef
instead:
import { useRef, useEffect } from 'react'; export default function AutoselectingInput() { const inputRef = useRef(null); useEffect(() => { const input = inputRef.current; input.select(); }, []); return <input ref={inputRef} defaultValue="Hello" /> }
¥Read more about manipulating the DOM with refs.
从转发的引用中读取子组件的 DOM 节点
¥Reading a child component’s DOM node from a forwarded ref
在此示例中,findDOMNode(this)
找到属于另一个组件的 DOM 节点。AutoselectingInput
渲染 MyInput
,这是渲染浏览器 <input>
的你自己的组件。
¥In this example, findDOMNode(this)
finds a DOM node that belongs to another component. The AutoselectingInput
renders MyInput
, which is your own component that renders a browser <input>
.
import { Component } from 'react'; import { findDOMNode } from 'react-dom'; import MyInput from './MyInput.js'; class AutoselectingInput extends Component { componentDidMount() { const input = findDOMNode(this); input.select() } render() { return <MyInput />; } } export default AutoselectingInput;
请注意,在 AutoselectingInput
中调用 findDOMNode(this)
仍然会为你提供 DOM <input>
- 即使此 <input>
的 JSX 隐藏在 MyInput
组件中。这对于上面的例子来说似乎很方便,但它会导致代码脆弱。假设你想稍后编辑 MyInput
并在其周围添加一个封装器 <div>
。这会破坏 AutoselectingInput
的代码(期望找到 <input>
)。
¥Notice that calling findDOMNode(this)
inside AutoselectingInput
still gives you the DOM <input>
—even though the JSX for this <input>
is hidden inside the MyInput
component. This seems convenient for the above example, but it leads to fragile code. Imagine that you wanted to edit MyInput
later and add a wrapper <div>
around it. This would break the code of AutoselectingInput
(which expects to find an <input>
).
要替换此示例中的 findDOMNode
,两个组件需要协调:
¥To replace findDOMNode
in this example, the two components need to coordinate:
-
AutoSelectingInput
应该像 在前面的例子中 一样声明一个引用,并将其传递给<MyInput>
。¥
AutoSelectingInput
should declare a ref, like in the earlier example, and pass it to<MyInput>
. -
MyInput
应该用forwardRef
声明以获取该引用并将其向下转发到<input>
节点。¥
MyInput
should be declared withforwardRef
to take that ref and forward it down to the<input>
node.
这个版本就是这样做的,所以它不再需要 findDOMNode
:
¥This version does that, so it no longer needs findDOMNode
:
import { createRef, Component } from 'react'; import MyInput from './MyInput.js'; class AutoselectingInput extends Component { inputRef = createRef(null); componentDidMount() { const input = this.inputRef.current; input.select() } render() { return ( <MyInput ref={this.inputRef} /> ); } } export default AutoselectingInput;
下面是使用函数组件而不是类时这段代码的样子:
¥Here is how this code would look like with function components instead of classes:
import { useRef, useEffect } from 'react'; import MyInput from './MyInput.js'; export default function AutoselectingInput() { const inputRef = useRef(null); useEffect(() => { const input = inputRef.current; input.select(); }, []); return <MyInput ref={inputRef} defaultValue="Hello" /> }
添加封装器 <div>
元素
¥Adding a wrapper <div>
element
有时一个组件需要知道它的子级的位置和大小。这让人很想找到 findDOMNode(this)
的子级,然后使用像 getBoundingClientRect
这样的 DOM 方法进行测量。
¥Sometimes a component needs to know the position and size of its children. This makes it tempting to find the children with findDOMNode(this)
, and then use DOM methods like getBoundingClientRect
for measurements.
目前这个用例没有直接的等价物,这就是为什么 findDOMNode
被弃用但尚未从 React 中完全删除的原因。同时,作为解决方法,你可以尝试在内容周围渲染一个封装器 <div>
节点,并获取对该节点的引用。但是,额外的封装器可能会破坏样式。
¥There is currently no direct equivalent for this use case, which is why findDOMNode
is deprecated but is not yet removed completely from React. In the meantime, you can try rendering a wrapper <div>
node around the content as a workaround, and getting a ref to that node. However, extra wrappers can break styling.
<div ref={someRef}>
{children}
</div>
这也适用于任意子项的聚焦和滚动。
¥This also applies to focusing and scrolling to arbitrary children.