useLayoutEffect + useState 与 useMemo 的用例

Use case for useLayoutEffect + useState vs useMemo

我看过这个答案:,它很好地总结了 useEffect,但在我的例子中,我想执行一个昂贵的操作来改变 DOM 越早越好。是否仍会推荐 useMemo() 而不是带有状态更新的 useLayoutEffect()?双渲染效果 -> 状态更新是否会抵消任何性能提升?

编辑

useLayoutEffect()场景:

useLayoutEffect(() => {
    const tokens = expensiveOperationGeneratingClasses(param1)
    setTokens(tokens)
}, 
[param1])

 render (
  <>
   {
       tokens.map(token => <span className={token.id}/>)
   }
  </>
 )

useMemo场景:

const tokens = useMemo(() => {
     return expensiveOperationGeneratingClasses(param1)
},
[param1]

 render (
  <>
   {
       tokens.map(token => <span className={token.id}/>)
   }
  </>
 )

实际上我意识到我不是在做 DOM 操作,而是只是在呈现 <span> 标签之前生成 class 名称以避免闪烁,所以我想我最好使用 useMemo,对吗?

我将尝试解释您可以在何处使用 LayoutEffect 和 Memo。先从LayoutEffect的使用说起吧。

Dan Abramov Link 1, Link 2.It's a good explanation of where you can use these gives Kent C. Dodds.If you need an example, you can see it here 说使用 LayoutEffect 有一些缺点。不要忘记阅读以了解差异。

现在介绍一下使用备忘录。它还有一个 drawback. For what we use Memo ,and where it is used you can found here.

现在正在实践中。

选项 1 使用 LayoutEffect

import React, { useState, useLayoutEffect } from "react";
import ReactDOM from "react-dom";

import "./styles.css";
const Control = () => {
  const [add, setAdd] = useState(1);
  return (
    <div>
      <div>
        <PostOffice add={add} />
      </div>
      <div onClick={() => setAdd(add + 1)}>{"Click"}</div>
    </div>
  );
};

function PostOffice({ add }) {
  const [letter, setLetter] = useState(add);

  useLayoutEffect(() => {
    console.log("useLayoutEffect");
    setLetter(add);
  }, [add]);

  console.log(letter);
  return <div className="App">{console.log(letter, "DOM")}</div>;
}

const rootElement = document.getElementById("root");
ReactDOM.render(<Control />, rootElement);

我不确定这个选项1,因为这里有一个

方案二使用LayoutEffect

import React, { useState, useLayoutEffect } from "react";
import ReactDOM from "react-dom";

import "./styles.css";
const Control = () => {
  const [add, setAdd] = useState(1);
  return (
    <div>
      <div>
        <PostOffice add={add} />
      </div>
      <div onClick={() => setAdd(add + 1)}>{"Click"}</div>
    </div>
  );
};

function PostOffice({ add }) {
  const [letter, setLetter] = useState(0);

  useLayoutEffect(() => {
    console.log("useLayoutEffect");
    setLetter(add);
  }, [add]);

  console.log(letter);
  return <div className="App">{console.log(letter, "DOM")}</div>;
}

const rootElement = document.getElementById("root");
ReactDOM.render(<Control />, rootElement);

会有无意义的渲染

选项 useMemo

import React, { useState, useMemo } from "react";
import ReactDOM from "react-dom";

import "./styles.css";
const Control = () => {
  const [add, setAdd] = useState(1);
  return (
    <div>
      <div>
        <PostOffice add={add} />
      </div>
      <div onClick={() => setAdd(add + 1)}>{"Click"}</div>
    </div>
  );
};

function PostOffice({ add }) {
  const Letter = useMemo(() => {
    console.log("useMemo");
    return add + 1;
  }, [add]);

  console.log(Letter);
  return <div className="App">{console.log(Letter, "DOM")}</div>;
}

const rootElement = document.getElementById("root");
ReactDOM.render(<Control />, rootElement);

这里一切正常

总计

减去 useMemo 1,

减去useLayoutEffect,1,anti-pattern效果或无意义渲染,加入useState,

这就是你应该使用 useMemo 的原因。

不过如果有办法不用这些钩子就完美了