Когда использовать useImperativeHandle, useLayoutEffect и useDebugValue - программирование
Подтвердить что ты не робот

Когда использовать useImperativeHandle, useLayoutEffect и useDebugValue

Я не могу понять, почему нужны следующие хуки useImperativeHandle, useLayoutEffect и useDebugValue, можете ли вы привести примеры, когда их можно использовать, а не примеры из документации, пожалуйста.

4b9b3361

Ответ 1

Позвольте мне предвосхитить этот ответ, заявив, что все эти крючки используются очень редко. 99% времени вам это не понадобится. Они предназначены только для того, чтобы охватить некоторые редкие сценарии на углу.


useImperativeHandle

Обычно, когда вы используете useRef вам дается значение экземпляра компонента, к ref прикреплен ref. Это позволяет вам напрямую взаимодействовать с элементом DOM.

useImperativeHandle очень похож, но он позволяет вам делать две вещи:

  1. Это дает вам контроль над значением, которое возвращается. Вместо того, чтобы возвращать элемент экземпляра, вы явно указываете, каким будет возвращаемое значение (см. Фрагмент ниже).
  2. Он позволяет заменять встроенные функции (такие как blur, focus и т.д.) Собственными функциями, что позволяет получить побочные эффекты для нормального поведения или совсем другого поведения. Впрочем, вы можете вызывать функцию как угодно.

Может быть много причин, по которым вы захотите сделать что-либо из вышеперечисленного; Возможно, вы не захотите предоставлять родные свойства родительскому объекту или хотите изменить поведение нативной функции. Там может быть много причин. Однако useImperativeHandle используется редко.

useImperativeHandle настраивает значение экземпляра, которое предоставляется родительским компонентам при использовании ref

пример

В этом примере значение, которое мы получим из ref будет содержать только функцию blur которую мы объявили в нашем useImperativeHandle. Он не будет содержать никаких других свойств (я регистрирую значение, чтобы продемонстрировать это). Сама функция также "настроена" на поведение, отличное от ожидаемого. Здесь он устанавливает document.title и размывает ввод, когда вызывается blur.

const MyInput = React.forwardRef((props, ref) => {
  const [val, setVal] = React.useState('');
  const inputRef = React.useRef();

  React.useImperativeHandle(ref, () => ({
    blur: () => {
      document.title = val;
      inputRef.current.blur();
    }
  }));

  return (
    <input
      ref={inputRef}
      val={val}
      onChange={e => setVal(e.target.value)}
      {...props}
    />
  );
});

const App = () => {
  const ref = React.useRef(null);
  const onBlur = () => {
    console.log(ref.current); // Only contains one property!
    ref.current.blur();
  };

  return <MyInput ref={ref} onBlur={onBlur} />;
};

ReactDOM.render(<App />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.1/umd/react-dom.production.min.js"></script>
<div id="app"></div>

Ответ 2

useImperativeHandle

Представьте, что вы создаете компонент Table. Вы можете указать, как refs на Table взаимодействуют с этим компонентом; может случиться так, что, например, вы хотите предоставить конкретную ячейку, а не только иметь доступ к корневому элементу.

[index.tsx]

import React, { useRef, useEffect } from "react";
import { render } from "react-dom";
import Table from "./Table";

import "./styles.css";

function App() {
  const tableRef = useRef(null);

  useEffect(() => {
    tableRef.current.style.color = "green";
  }, []);

  return (
    <div>
      <Table ref={tableRef} />
    </div>
  );
}

const rootElement = document.getElementById("root");
render(<App />, rootElement);

[Table.tsx]

import React, { useRef, useImperativeHandle, forwardRef } from "react";

function Table(props, ref) {
  const cellRef = useRef(null);
  useImperativeHandle(ref, () => cellRef.current);

  return (
    <table>
      <tr>
        <td>First</td>
        <td ref={cellRef}>Second</td>
      </tr>
    </table>
  );
}

export default forwardRef(Table);

Доступно здесь.

useLayoutEffect

Это то же самое, что и useEffect, но срабатывает только после завершения всех мутаций DOM. В этой статье Кента С. Доддса, как и всех остальных, объясняется разница, касающаяся этих двух, он говорит:

99% времени [ useEffect ] - это то, что вы хотите использовать.

Я не видел примеров, которые бы это особенно хорошо иллюстрировали, и я не уверен, что смогу что-либо создать. Вероятно, лучше сказать, что вы должны использовать useLayoutEffect только когда у useEffect есть проблемы.

useDebugValue

Я чувствую, что документы делают довольно хороший пример объяснения этого. Если у вас есть пользовательский хук, и вы хотите пометить его в React DevTools, то это то, что вы используете.

Если у вас есть какие-то конкретные проблемы с этим, то, вероятно, было бы лучше либо прокомментировать, либо задать другой вопрос, потому что я чувствую, что все, что люди здесь размещают, будет просто повторять документы, по крайней мере, пока мы не достигнем более конкретной проблемы.