Я не могу понять, почему нужны следующие хуки useImperativeHandle, useLayoutEffect и useDebugValue, можете ли вы привести примеры, когда их можно использовать, а не примеры из документации, пожалуйста.
Когда использовать useImperativeHandle, useLayoutEffect и useDebugValue
Ответ 1
Позвольте мне предвосхитить этот ответ, заявив, что все эти крючки используются очень редко. 99% времени вам это не понадобится. Они предназначены только для того, чтобы охватить некоторые редкие сценарии на углу.
useImperativeHandle
Обычно, когда вы используете useRef
вам дается значение экземпляра компонента, к ref
прикреплен ref
. Это позволяет вам напрямую взаимодействовать с элементом DOM.
useImperativeHandle
очень похож, но он позволяет вам делать две вещи:
- Это дает вам контроль над значением, которое возвращается. Вместо того, чтобы возвращать элемент экземпляра, вы явно указываете, каким будет возвращаемое значение (см. Фрагмент ниже).
- Он позволяет заменять встроенные функции (такие как
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, то это то, что вы используете.
Если у вас есть какие-то конкретные проблемы с этим, то, вероятно, было бы лучше либо прокомментировать, либо задать другой вопрос, потому что я чувствую, что все, что люди здесь размещают, будет просто повторять документы, по крайней мере, пока мы не достигнем более конкретной проблемы.