useLayoutEffect + useState与useMemo的用例

P F*_*ter 6 reactjs react-hooks

我已经看到了这个答案:useMemo vs. useEffect + useState,它总结起来很不错useEffect,但就我而言,我想执行一个昂贵的操作,该操作将尽早更改DOM。将useMemo()仍然被代替的建议useLayoutEffect()与状态更新?效果的双重渲染->状态更新会否提高性能?

编辑

useLayoutEffect() 场景:

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

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

Run Code Online (Sandbox Code Playgroud)

useMemo 场景:

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

 render (
  <>
   {
       tokens.map(token => <span className={token.id}/>)
   }
  </>
 )
Run Code Online (Sandbox Code Playgroud)

实际上,我意识到我不是在进行DOM操作,而是在呈现<span>标记之前生成类名以避免闪烁,所以我认为我最好使用useMemo,对吗?

Edg*_*gar 3

我将尝试解释在哪里可以使用 LayoutEffect 和 Memo。让我们从 LayoutEffect 的使用开始。

Dan Abramov Link 1Link 2表示,使用 LayoutEffect 有一些缺点。Kent C很好地解释了在哪里可以使用这些。Dodds。如果您需要示例,可以在这里查看Chris。不要忘记阅读以了解差异。

现在介绍一下 Memo 的使用。它也有一个缺点。对于我们使用 Memo 的内容以及使用它的位置,您可以在这里找到。

现在正在实践中。

选项 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);
Run Code Online (Sandbox Code Playgroud)

我不确定这个选项1,因为这里有一个反模式效果

选项 2 使用 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);
Run Code Online (Sandbox Code Playgroud)

会有无意义的渲染

选项 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);
Run Code Online (Sandbox Code Playgroud)

这里一切都很完美

全部的

减去 useMemo 1

减去 useLayoutEffect, 1,反模式效果或无意义渲染,添加 useState,

这就是为什么你应该使用 useMemo。

但如果有办法不使用这些钩子那就完美了。