findDOMNode

Цей API буде видалено у наступному старшому релізі React. Дивіться альтернативи.

findDOMNode знаходить вузол DOM браузера для компонента React class instance.

const domNode = findDOMNode(componentInstance)

Довдіник

findDOMNode(componentInstance)

Виклик findDOMNode для пошуку DOM-вузла браузера для заданого екземпляра класу компонента React.

import { findDOMNode } from 'react-dom';

const domNode = findDOMNode(componentInstance);

Дивіться більше прикладів нижче.

Параметри

  • componentInstance: Екземпляр підкласу Component. Наприклад, це всередині класу component.

Повернення

findDOMNode повертає перший найближчий DOM-вузол браузера в межах заданого componentInstance. Коли компонент рендерить до null або рендерить false, findDOMNode повертає null. Коли компонент рендериться у рядок, findDOMNode повертає текстовий DOM-вузол, що містить це значення.

Застереження

  • Компонент може повертати масив або Фрагмент з декількома дочірніми елементами. У такому випадку findDOMNode, поверне вузол DOM, що відповідає першому непорожньому дочірньому елементу.

  • findDOMNode працює лише на змонтованих компонентах (тобто компонентах, які було розміщено у DOM). Якщо ви спробуєте викликати його у компоненті, який ще не змонтовано (наприклад, викликати findDOMNode() у render() у компоненті, який ще не створено), буде згенеровано виключення.

  • findDOMNode повертає лише результат на момент вашого виклику. Якщо дочірній компонент відрендерить інший вузол пізніше, ви не отримаєте сповіщення про цю зміну.

  • findDOMNode приймає екземпляр компонента класу, тому його не можна використовувати з компонентами функцій.


Використання

Знаходження кореневого вузла DOM компонента класу

Виклик findDOMNode з екземпляром компонента класу (зазвичай, це), щоб знайти вузол DOM, який він відрендерив.

class AutoselectingInput extends Component {
  componentDidMount() {
    const input = findDOMNode(this);
    input.select()
  }

  render() {
    return <input defaultValue="Hello" />
  }
}

Тут змінну input буде встановлено на DOM-елемент <input>. Це дозволяє вам робити з нею якісь дії. Наприклад, при натисканні кнопки "Показати приклад" нижче монтується введення, input.select() виділяє весь текст у введенні:

import { useState } from 'react';
import AutoselectingInput from './AutoselectingInput.js';

export default function App() {
  const [show, setShow] = useState(false);
  return (
    <>
      <button onClick={() => setShow(true)}>
        Show example
      </button>
      <hr />
      {show && <AutoselectingInput />}
    </>
  );
}
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;

Альтернативи

Читання власного DOM-вузла компонента з посилання

Код з використанням findDOMNode є крихким, оскільки зв'язок між вузлом JSX та кодом, що маніпулює відповідним вузлом DOM, не є явним. Наприклад, спробуйте обгорнути цей <input /> у <div>:

import { useState } from 'react';
import AutoselectingInput from './AutoselectingInput.js';

export default function App() {
  const [show, setShow] = useState(false);
  return (
    <>
      <button onClick={() => setShow(true)}>
        Show example
      </button>
      <hr />
      {show && <AutoselectingInput />}
    </>
  );
}
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) знаходить вузол DOM <div>, але код очікує вузол DOM <input>. Щоб уникнути подібних проблем, використовуйте createRef для керування конкретним вузлом DOM.

У цьому прикладі findDOMNode більше не використовується. Натомість, inputRef = createRef(null) визначено як поле екземпляра класу. Щоб прочитати DOM-вузол з нього, можна використовувати this.inputRef.current. Щоб приєднати його до JSX, ви рендерите <input ref={this.inputRef} />. Це з'єднає код, що використовує вузол DOM, з його JSX:

import { useState } from 'react';
import AutoselectingInput from './AutoselectingInput.js';

export default function App() {
  const [show, setShow] = useState(false);
  return (
    <>
      <button onClick={() => setShow(true)}>
        Show example
      </button>
      <hr />
      {show && <AutoselectingInput />}
    </>
  );
}
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 { useState } from 'react';
import AutoselectingInput from './AutoselectingInput.js';

export default function App() {
  const [show, setShow] = useState(false);
  return (
    <>
      <button onClick={() => setShow(true)}>
        Show example
      </button>
      <hr />
      {show && <AutoselectingInput />}
    </>
  );
}
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 за допомогою посилань.


Читання DOM-вузла дочірнього компонента з перенаправленого посилання

У цьому прикладі findDOMNode(this) знаходить вузол DOM, який належить іншому компоненту. AutoselectingInput рендерить MyInput, який є вашим власним компонентом, що рендерить браузер <input>.

import { useState } from 'react';
import AutoselectingInput from './AutoselectingInput.js';

export default function App() {
  const [show, setShow] = useState(false);
  return (
    <>
      <button onClick={() => setShow(true)}>
        Show example
      </button>
      <hr />
      {show && <AutoselectingInput />}
    </>
  );
}
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;
export default function MyInput() {
  return <input defaultValue="Hello" />;
}

Зверніть увагу, що виклик findDOMNode(this) всередині AutoselectingInput все одно дає вам DOM <input> - навіть якщо JSX для цього <input> приховано всередині компонента MyInput. Це здається зручним для наведеного вище прикладу, але призводить до нестійкого коду. Уявіть, що ви захочете пізніше відредагувати MyInput і додати до нього обгортку <div>. Це зламає код AutoselectingInput (який очікує знайти <input>).

Для заміни findDOMNode у цьому прикладі потрібно узгодити два компоненти:

  1. AutoSelectingInput слід оголосити реф, як у попередньому прикладі , і передати його до <MyInput>.
  2. MyInput слід оголосити з forwardRef, щоб взяти це посилання і переслати його до вузла <input>.

Ця версія робить це, тому їй більше не потрібні findDOMNode:

import { useState } from 'react';
import AutoselectingInput from './AutoselectingInput.js';

export default function App() {
  const [show, setShow] = useState(false);
  return (
    <>
      <button onClick={() => setShow(true)}>
        Show example
      </button>
      <hr />
      {show && <AutoselectingInput />}
    </>
  );
}
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 { forwardRef } from 'react';

const MyInput = forwardRef(function MyInput(props, ref) {
  return <input ref={ref} defaultValue="Hello" />;
});

export default MyInput;

Ось як виглядав би цей код з функціональними компонентами замість класів:

import { useState } from 'react';
import AutoselectingInput from './AutoselectingInput.js';

export default function App() {
  const [show, setShow] = useState(false);
  return (
    <>
      <button onClick={() => setShow(true)}>
        Show example
      </button>
      <hr />
      {show && <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" />
}
import { forwardRef } from 'react';

const MyInput = forwardRef(function MyInput(props, ref) {
  return <input ref={ref} defaultValue="Hello" />;
});

export default MyInput;

Додавання обгортки <div>елемента

Іноді компоненту потрібно знати положення та розмір своїх дочірніх елементів. Це створює спокусу знайти дочірні елементи за допомогою findDOMNode(this), а потім використати методи DOM на кшталт getBoundingClientRect для обчислень.

Наразі не існує прямого еквіваленту для цього варіанту використання, тому findDOMNode застаріла, але ще не видалена повністю з React. Тим часом, ви можете спробувати відрендерити вузол-обгортку <div> навколо вмісту як обхідний шлях і отримати посилання на цей вузол. Однак, додаткові обгортки можуть порушити стилізацію.

<div ref={someRef}>
  {children}
</div>

Це також стосується фокусування та прокрутки до довільних дочірніх елементів.