findDOMNode
用于查找 React 类组件 实例的浏览器 DOM 节点。
const domNode = findDOMNode(componentInstance)
参考
findDOMNode(componentInstance)
调用 findDOMNode
来查找给定的 React 类组件 实例的浏览器 DOM 节点。
import { findDOMNode } from 'react-dom';
const domNode = findDOMNode(componentInstance);
参数
componentInstance
:Component
子类的实例。例如,类组件内部的this
。
返回值
findDOMNode
返回给定 componentInstance
中第一个最接近的浏览器 DOM 节点。当组件渲染为 null
或渲染为 false
时,findDOMNode
返回 null
。当组件渲染为字符串时,findDOMNode
返回一个包含该值的文本 DOM 节点。
注意事项
-
组件可以返回一个数组或包含多个子元素的 Fragment。在这种情况下,
findDOMNode
将返回与第一个非空子元素对应的 DOM 节点。 -
findDOMNode
仅适用于已挂载的组件(即已放置在 DOM 中的组件)。如果你尝试在尚未挂载的组件上调用它(例如在尚未创建的组件的render()
中调用findDOMNode()
),则会抛出异常。 -
findDOMNode
仅返回调用时的结果。如果子组件稍后渲染了不同的节点,则无法通知你此更改。 -
findDOMNode
接受类组件实例,因此不能将其与函数组件一起使用。
用法
查找类组件的根 DOM 节点
使用 类组件 实例(通常为 this
)调用 findDOMNode
来查找它已渲染的 DOM 节点。
class AutoselectingInput extends Component {
componentDidMount() {
const input = findDOMNode(this);
input.select()
}
render() {
return <input defaultValue="Hello" />
}
}
在这里,input
变量将被设置为 <input>
DOM 元素。这使你可以对其进行操作。例如,当点击下方“显示示例”以挂载输入框时,input.select()
会选中输入框中的所有文本
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;
替代方案
从 ref 中读取组件自身的 DOM 节点
使用 findDOMNode
的代码很脆弱,因为 JSX 节点与操作相应 DOM 节点的代码之间的连接并不明确。例如,尝试将此 <input />
包装到 <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 节点。
在此示例中,不再使用 findDOMNode
。而是将 inputRef = createRef(null)
定义为类上的实例字段。要从中读取 DOM 节点,可以使用 this.inputRef.current
。要将其附加到 JSX,可以渲染 <input ref={this.inputRef} />
。这会将使用 DOM 节点的代码与其 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
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" /> }
从转发的 ref 中读取子组件的 DOM 节点
在此示例中,findDOMNode(this)
找到属于另一个组件的 DOM 节点。AutoselectingInput
渲染 MyInput
,它是渲染浏览器 <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>
元素)。
要在此示例中替换 findDOMNode
,这两个组件需要进行协调:
AutoSelectingInput
应该声明一个 ref,就像前面的示例中那样,并将其传递给<MyInput>
。MyInput
应该使用forwardRef
声明,以接收该 ref 并将其向下传递给<input>
节点。
这个版本就是这样做的,所以它不再需要 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;
以下是使用函数组件而不是类组件的代码:
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>
元素
有时,组件需要知道其子组件的位置和大小。这会让人很想使用 findDOMNode(this)
查找子组件,然后使用 getBoundingClientRect
等 DOM 方法进行测量。
目前还没有直接等效的方法来解决这个用例,这就是为什么 findDOMNode
被弃用但尚未从 React 中完全删除的原因。在此期间,您可以尝试在内容周围渲染一个包装器 <div>
节点作为一种解决方法,并获取对该节点的引用。但是,额外的包装器可能会破坏样式。
<div ref={someRef}>
{children}
</div>
这也适用于聚焦和滚动到任意子组件。