- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我不明白为什么需要以下 useImperativeHandle
、useLayoutEffect
和 useDebugValue
钩子(Hook),您能否举例说明何时可以使用它们,但请不要使用文档中的示例。
最佳答案
请允许我在这个答案的前言中指出,所有这些钩子(Hook)都很少使用。 99% 的情况下,您不需要这些。它们只是为了涵盖一些罕见的极端情况。
<小时/>useImperativeHandle
通常,当您使用 useRef
时,您会获得 ref
所附加到的组件的实例值。这允许您直接与 DOM 元素交互。
useImperativeHandle
非常相似,但它可以让您做两件事:
blur
、focus
等),从而允许对正常行为产生副作用,或者完全不同的行为。不过,您可以随意调用该函数。您可能出于多种原因想要执行上述任一操作;您可能不想向父级公开 native 属性,或者您可能想更改 native 函数的行为。原因可能有很多。但是,useImperativeHandle
很少使用。
useImperativeHandle
customizes the instance value that is exposed to parent components when usingref
示例
在此示例中,我们从 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 insideuseLayoutEffect
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/
我有以下组件: // component.js import React from 'react'; import useComponentSize from 'useComponentSize';
据我所知,useLayoutEffect 同步运行,而 useEffect 异步运行 - 或多或少就像我们使用 useLayoutEffect 一样,但是setTimeout(func,0)。 use
我们如何模仿 useLayoutEffect() 的功能?在类组件中? 假设我们的功能组件是 function MyFuncComponent() { useLayoutEffect(() =>
关于 useLayoutEffect 的区别之一对比 useEffect是useLayoutEffect将在 DOM 突变之后和浏览器绘制阶段之前同步触发。 (Reference) 但是,我遇到了一些
我看过这个答案:useMemo vs. useEffect + useState ,它很好地总结了 useEffect ,但就我而言,我想执行一项昂贵的操作来尽早更改 DOM。会useMemo()仍然
完整错误如下: Warning: useLayoutEffect does nothing on the server, because itseffect cannot be encoded int
useMutationEffect 和 useLayoutEffect 在使用方面有什么区别? 我已阅读所有在线可用 Material ,包括(但不限于) Hooks Reference Blog p
我不明白为什么需要以下 useImperativeHandle、useLayoutEffect 和 useDebugValue 钩子(Hook),您能否举例说明何时可以使用它们,但请不要使用文档中的示
我正在使用 React v.16.12.0 和 @MaterialUI/core v4.8.1。 我正在尝试为 React Leaflet Marker 创建自定义图标。图标是 Fab Materia
我想从 React Native 的标题底部删除模糊的边框。我正在使用 useLayoutEffect()钩子(Hook)修改标题但无法删除边框。我试过使用 borderBottomWidth: 0里
在官方 React 文档中,对于 useLayoutEffect ,其中提到: The signature is identical to useEffect, but it fires synchr
我有一个组件,我想在屏幕上呈现 HTML 之前进行一些计算。由于useEffect和 useLayoutEffect可以处理这个任务,我的问题是它们都在代码中,它们中的哪一个将首先被触发,useEff
我是一名优秀的程序员,十分优秀!