Reputation: 2334
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?
Upvotes: 5
Views: 3017
Reputation: 6856
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.
Upvotes: 3