findDOMNode

弃用

这个 API 将在 React 的未来主要版本中被删除。查看备选方案。

¥This API will be removed in a future major version of React. See the alternatives.

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);

请参阅下面的更多示例。

¥See more examples below.

参数

¥Parameters

  • componentInstanceComponent 子类的实例。例如,类组件中的 this

    ¥componentInstance: An instance of the Component subclass. For example, this inside a class component.

返回

¥Returns

findDOMNode 返回给定 componentInstance 中第一个最近的浏览器 DOM 节点。当一个组件渲染到 null,或者渲染 falsefindDOMNode 返回 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() in render()),将会抛出异常。

    ¥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 calling findDOMNode() in render() 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" />
}

阅读更多关于使用引用操作 DOM 的内容。

¥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:

  1. AutoSelectingInput 应该像 在前面的例子中 一样声明一个引用,并将其传递给 <MyInput>

    ¥AutoSelectingInput should declare a ref, like in the earlier example, and pass it to <MyInput>.

  2. MyInput 应该用 forwardRef 声明以获取该引用并将其向下转发到 <input> 节点。

    ¥MyInput should be declared with forwardRef 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.


React 中文网 - 粤ICP备13048890号