当前位置: 首页 > 面试题库 >

何时使用useImperativeHandle,useLayoutEffect和useDebugValue

赫连永怡
2023-03-14
问题内容

我不明白为什么需要以下useImperativeHandleuseLayoutEffectuseDebugValue挂钩,可以在使用时提供示例,但请从文档中获取示例。


问题答案:

请允许我先说所有这些挂钩很少使用,以此作为开头的答案。99%的时间,您将不需要这些。它们仅旨在涵盖一些罕见的极端情况。

useImperativeHandle

通常,在使用时会为useRef您提供ref附加到该组件的实例值。这使您可以直接与DOM元素进行交互。

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

  1. 它使您可以控制返回的值。您无需显式声明返回值,而无需返回instance元素(请参见下面的代码段)。
  2. 它可以让你更换本地函数(如blurfocus用自己的功能,等等),从而使副作用的正常行为,或者不同的行为完全。虽然,您可以随意调用该函数。

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

useImperativeHandle 自定义使用时暴露给父组件的实例值 ref

在此示例中,我们将从中获得的值ref将仅包含在中blur声明的函数useImperativeHandle。它不会包含任何其他属性(
我正在记录该值来演示此内容
)。该函数本身也被“定制”为与通常期望的行为不同。在这里,它会document.titleblur调用时设置和模糊输入。

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提交更新后运行。在极少数情况下用于需要在更新后计算元素之间的距离或进行其他更新后计算/副作用的情况。

签名与相同useEffect,但在所有DOM突变后都会同步触发。使用它从DOM读取布局并同步重新渲染。 在浏览器有机会绘制之前,*
计划在内部useLayoutEffect进行的更新将被同步刷新。
*

假设您有一个绝对定位的元素,其高度可能会变化,并且您想div在其下放置另一个元素。您可以getBoundingCLientRect()用来计算父项的身高和top属性,然后将其应用于孩子的top属性。

在这里您要使用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并检查相关钩子时调用,以防止对性能产生任何影响。

useDebugValue 可用于在React DevTools中显示自定义钩子的标签。

我个人从来没有使用过这个钩子。也许评论中的某人可以通过一个很好的例子给出一些见解。



 类似资料:
  • forward ref 的对应项,useImperativeMethods 自定义使用 ref 时公开给父组件的实例值。useImperativeMethods 应与 forwardRef 一起使用: import { useImperativeHandle, useRef, forwardRef } from 'rax'; function FancyInput(props, ref) {

  • 与 useEffect 相同,但在所有 DOM 变化后它会同步触发。在浏览器有机会绘制之前,将在 useLayoutEffect 内部的逻辑同步触发。 在尽可能的情况下首选标准的 useEffect ,以避免阻止视觉更新。 import { useLayoutEffect } from 'rax'; function Example() { const [count, setCount] =

  • 本文向大家介绍useEffect和useLayoutEffect有什么区别?相关面试题,主要包含被问及useEffect和useLayoutEffect有什么区别?时的应答技巧和注意事项,需要的朋友参考一下 useEffect是异步的,所谓的异步就是利用requestIdleCallback,在浏览器空闲时间执行传入的callback。大部分情况下,用哪一个都是一样的,如果副作用执行比较长,比如大

  • 我已经看到了这个答案:useMemo vs.Useffect useState,它对进行了很好的总结,但在我的例子中,我希望执行一个昂贵的操作,尽早改变DOM。是否仍然建议使用带有状态更新的而不是?双重渲染效果如何- 编辑 场景: 场景: 实际上,我意识到我不是在做DOM操作,而是在呈现

  • 问题内容: 我一直在nodejs中编程,研究了如何同时使用socket.io和对节点服务器的ajax调用。socket.io是否设计为替代ajax?我很好奇,在哪种情况下使用socket.io更好,而哪种ajax更好。感谢您的输入。 问题答案: 好吧,Web套接字(通过socket.io)提供的主要内容之一就是ajax缺乏的是服务器推送。因此,对于ajax,如果您想了解服务器上的新事件(例如,另一

  • 问题内容: 我得到了asyncio在Python 3.5 中使用的流程,但是我还没有看到关于我应该使用什么东西,我不应该使用的await东西或者它在哪里容易出现的描述。我是否仅需要根据“这是IO操作并应进行await编辑” 来做出最好的判断? 问题答案: 默认情况下,所有代码都是同步的。你可以使用使其异步定义函数,async def并使用来“调用”这些函数await。一个更正确的问题是“什么时候应