findDOMNode

已弃用

此 API 将在未来主要版本的 React 中移除。 查看替代方案。

findDOMNode 用于查找 React 类组件 实例的浏览器 DOM 节点。

const domNode = findDOMNode(componentInstance)

参考

findDOMNode(componentInstance)

调用 findDOMNode 来查找给定的 React 类组件 实例的浏览器 DOM 节点。

import { findDOMNode } from 'react-dom';

const domNode = findDOMNode(componentInstance);

请在下方查看更多示例。

参数

  • componentInstanceComponent 子类的实例。例如,类组件内部的 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 的更多信息。


从转发的 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,这两个组件需要进行协调:

  1. AutoSelectingInput 应该声明一个 ref,就像前面的示例中那样,并将其传递给 <MyInput>
  2. 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>

这也适用于聚焦和滚动到任意子组件。