繁体   English   中英

使用 `useEffect()` 与 `useLayoutEffect()` 的 DOM 操作

[英]DOM Manipulation With `useEffect()` vs. `useLayoutEffect()`

在我的应用程序组件中,我有:

function App() {
  
  const appRef = useRef();
  
  return (
    <div
      ref={appRef}
      className="app position-relative overflow-hidden"
      dir="rtl"
    >
      <NavBar cssCalsses="py-14 px-20 px-lg-0" />
      <Switch>
        <Route exact path="/">
          <HomePage appRef={appRef} />
        </Route>
        <Route exact path="/tariff">
          <TariffPage appRef={appRef} />
        </Route>
        <Route exact path="/blog">
          <MagazinesPage appRef={appRef} />
        </Route>
        <Route exact path="/blog/:blogId">
          <MagazinePage appRef={appRef} />
        </Route>
        <Route exact path="/free-class">
          <FreeClass appRef={appRef} />
        </Route>
        <Route exact path="/room-log">
          <RoomLog appRef={appRef} />
        </Route>
        <Route>
          <NotFound appRef={appRef} />
        </Route>
      </Switch>
      <MainFooter />
    </div>
  );
}

在每个页面组件中,我都有类似的内容:

useEffect(() => {
    appRef.current.style.background =
      "background value ...";
  }, [appRef]);

现在,如果我将useEffect更改为 useLayoutEffect , useLayoutEffect收到Cannot read property 'style' of undefined错误。

如果我像下面这样使用它,我不会有任何错误:

useLayoutEffect(() => {
        document.querySelector('.app').style.background =
          "background value ...";
      }, [appRef]);

现在:

  1. 为什么会这样?
  2. 哪一个更好?? 使用 react refuseEffect操作dom 或者用querySelectoruseLayoutEffect

为了解决您的第一个问题,我创建了一个代码框

代码:-

import { useLayoutEffect, useEffect, useRef } from "react";
import "./styles.css";

export default function App() {
  const appRef = useRef();

  console.log("parent render start");
  useLayoutEffect(() => {
    console.log("parent layoutEffect", appRef.current.style);
  }, [appRef]);

  useEffect(() => {
    console.log("parent effect", appRef.current.style);
  }, [appRef]);
  console.log("parent render end");
  return (
    <div ref={appRef} className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <Child appRef={appRef} />
    </div>
  );
}

function Child({ appRef }) {
  console.log("child render start");
  useLayoutEffect(() => {
    console.log("child layoutEffect", appRef.current.style);
  }, [appRef]);

  useEffect(() => {
    console.log("child effect", appRef.current.style);
  }, [appRef]);

  console.log("child render end");
  return <></>;
}

OUTPUT:-

parent render start

parent render end

child render start

child render end

child layoutEffect undefined

parent layoutEffect CSSStyleDeclaration {alignContent: "", alignItems: "", alignSelf: "", alignmentBaseline: "", all: ""…}

child effect CSSStyleDeclaration {alignContent: "", alignItems: "", alignSelf: "", alignmentBaseline: "", all: ""…}

parent effect CSSStyleDeclaration {alignContent: "", alignItems: "", alignSelf: "", alignmentBaseline: "", all: ""…}

从上面我们可以看出:-

  • 孩子的useLayoutEffectappRef作为依赖项在父母的useLayoutEffectappRef之前运行。 在那之前appRef仍然是undefined的,因为ReactuseLayoutEffect之前更新了 DOM。 因此,除非DOM 已更新,否则appRef不会设置为子元素所需的DOM 元素

  • 另一方面,孩子的useEffectappRef父母的useLayoutEffectappRef之后运行。 这就是为什么appRef具有正确的 DOM 元素值的原因。

代码沙盒

这是一个很好的流程图来参考这个 - https://github.com/donavon/hook-flow

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM