Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use case for useLayoutEffect + useState vs useMemo

I've seen this answer: useMemo vs. useEffect + useState , and it sums it up well for useEffect, but in my case I want to perform an expensive operation that will change the DOM as early as possible. Would useMemo() still be recommended instead of useLayoutEffect() with a state update? Does the double render of effect -> state-update negate any performance boost?

EDIT

useLayoutEffect() scenario:

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

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

useMemo scenario:

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

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

Actually I realised that I'm not doing DOM operations but rather just generating the class names before the rendering of the <span> tags to avoid flickering, so I think i'm better off using useMemo, am I right?

like image 746
P Fuster Avatar asked Jul 14 '19 20:07

P Fuster


People also ask

What is the difference between useState and useMemo?

The difference is that: useMemo does not cause a re-render, while useState does. useMemo only runs when its dependencies (if any) have changed, while setSomeState (second array item returned by useState ) does not have such a dependency array.

Why do you use useLayoutEffect?

The useLayoutEffect function is triggered synchronously before the DOM mutations are painted. However, the useEffect function is called after the DOM mutations are painted. I chose this example to make sure the browser actually has some changes to paint when the button is clicked, hence the animation.

In which situation would you use useMemo () in React?

Performance. The useMemo Hook can be used to keep expensive, resource intensive functions from needlessly running. In this example, we have an expensive function that runs on every render. When changing the count or adding a todo, you will notice a delay in execution.

What is the difference between useEffect () and useLayoutEffect ()?

useLayoutEffect is identical to useEffect, but it's major key difference is that it gets triggered synchronously after all DOM mutation. You only want to use this hook when you need to do any DOM changes directly.


1 Answers

I will try to explain where you can use LayoutEffect and Memo. Let's start with the using of LayoutEffect.

The using of LayoutEffect has some drawbacks says 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 Chris. Don't forget about reading for understand the difference.

Now about of the using Memo. It's also has a drawback. For what we use Memo ,and where it is used you can found here.

And now in practice.

option 1 use 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);

I'm not sure about this option 1, because there is an anti-pattern effect here.

option 2 use 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);

there will be a meaningless rendering

option 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);

And here everything works perfectly

Total

Minus useMemo 1,

Minus useLayoutEffect, 1,anti-pattern effect or meaningless rendering,adding useState,

This is why you should use useMemo.

but if there is a way not to use these hooks, it will be perfect.

like image 159
Silicum Silium Avatar answered Sep 30 '22 16:09

Silicum Silium