gpt4 book ai didi

reactjs - 何时使用 useImperativeHandle、useLayoutEffect 和 useDebugValue

转载 作者:行者123 更新时间:2023-12-03 13:10:22 24 4
gpt4 key购买 nike

我不明白为什么需要以下 useImperativeHandleuseLayoutEffectuseDebugValue 钩子(Hook),您能否举例说明何时可以使用它们,但请不要使用文档中的示例。

最佳答案

请允许我在这个答案的前言中指出,所有这些钩子(Hook)都很少使用。 99% 的情况下,您不需要这些。它们只是为了涵盖一些罕见的极端情况。

<小时/>

useImperativeHandle

通常,当您使用 useRef 时,您会获得 ref 所附加到的组件的实例值。这允许您直接与 DOM 元素交互。

useImperativeHandle 非常相似,但它可以让您做两件事:

  1. 它使您可以控制返回的值。您不返回实例元素,而是明确说明返回值是什么(请参见下面的代码片段)。
  2. 它允许您用自己的函数替换 native 函数(例如 blurfocus 等),从而允许对正常行为产生副作用,或者完全不同的行为。不过,您可以随意调用该函数。

您可能出于多种原因想要执行上述任一操作;您可能不想向父级公开 native 属性,或者您可能想更改 native 函数的行为。原因可能有很多。但是,useImperativeHandle很少使用。

useImperativeHandle customizes the instance value that is exposed to parent components when using ref

示例

在此示例中,我们从 ref 获取的值将仅包含我们在 useImperativeHandle 中声明的函数 blur。它不会包含任何其他属性(我正在记录该值来演示这一点)。该函数本身也经过“定制”,其行为与您通常期望的不同。在这里,它设置 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>

<小时/>

useLayoutEffect

虽然在某种程度上类似于 useEffect(),但不同之处在于它将在 React 向 DOM 提交更新后运行。在极少数情况下使用,当您需要在更新后计算元素之间的距离或进行其他更新后计算/副作用时。

The signature is identical to useEffect, but it fires synchronously after all DOM mutations. Use this to read layout from the DOM and synchronously re-render. Updates scheduled inside useLayoutEffect will be flushed synchronously, before the browser has a chance to paint.

示例

假设您有一个绝对定位的元素,其高度可能会有所不同,并且您想在其下方放置另一个 div 。您可以使用 getBoundingClientRect() 计算父级的高度和顶部属性,然后将它们应用到子级的顶部属性。

在这里,您需要使用 useLayoutEffect 而不是 useEffect。在下面的示例中了解原因:

使用useEffect:(注意跳跃行为)

const Message = ({boxRef, children}) => {
const msgRef = React.useRef(null);
React.useEffect(() => {
const rect = boxRef.current.getBoundingClientRect();
msgRef.current.style.top = `${rect.height + rect.top}px`;
}, []);

return <span ref={msgRef} className="msg">{children}</span>;
};

const App = () => {
const [show, setShow] = React.useState(false);
const boxRef = React.useRef(null);

return (
<div>
<div ref={boxRef} className="box" onClick={() => setShow(prev => !prev)}>Click me</div>
{show && <Message boxRef={boxRef}>Foo bar baz</Message>}
</div>
);
};

ReactDOM.render(<App />, document.getElementById("app"));
.box {
position: absolute;
width: 100px;
height: 100px;
background: green;
color: white;
}

.msg {
position: relative;
border: 1px solid red;
}
<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>

使用useLayoutEffect:

const Message = ({boxRef, children}) => {
const msgRef = React.useRef(null);
React.useLayoutEffect(() => {
const rect = boxRef.current.getBoundingClientRect();
msgRef.current.style.top = `${rect.height + rect.top}px`;
}, []);

return <span ref={msgRef} className="msg">{children}</span>;
};

const App = () => {
const [show, setShow] = React.useState(false);
const boxRef = React.useRef(null);

return (
<div>
<div ref={boxRef} className="box" onClick={() => setShow(prev => !prev)}>Click me</div>
{show && <Message boxRef={boxRef}>Foo bar baz</Message>}
</div>
);
};

ReactDOM.render(<App />, document.getElementById("app"));
.box {
position: absolute;
width: 100px;
height: 100px;
background: green;
color: white;
}

.msg {
position: relative;
border: 1px solid red;
}
<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>

<小时/>

useDebugValue

有时您可能想要调试某些值或属性,但这样做可能需要昂贵的操作,这可能会影响性能。

useDebugValue 仅在 React DevTools 打开并检查相关钩子(Hook)时调用,防止对性能产生任何影响。

useDebugValue can be used to display a label for custom hooks in React DevTools.

不过我个人从未使用过这个钩子(Hook)。也许评论中的人可以通过一个很好的例子来提供一些见解。

关于reactjs - 何时使用 useImperativeHandle、useLayoutEffect 和 useDebugValue,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57005663/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com