useEffectとuseLayoutEffectの今ままでの認識ついて
useEffectとuseLayoutEffectの詳しい説明は省きますが、ざっくり以下のように考えていて
実行タイミングが違うだけで片方のみ実行されるタイミングがあるとは思っていませんでした。
useEffect:ブラウザが画面を描画した後に実行される
useLayoutEffect:ブラウザが画面を描画する前に実行される
詳しい説明用URL
useEffect公式記事
useLayoutEffect公式記事
ReactCompleteGuide(useEffect)
ReactLifecycle
調査結果
調べてみたところSuspence時にはuseEffectは実行されず、useLayoutEffectは実行されるようでした。
App.tsx
import { Suspense, useState } from "react";
import { TestComponent } from "./TestComponet";
import { Footer } from "./Footer";
function App() {
const [isSuspence, SetIsSuspence] = useState(false);
return (
<>
<Suspense fallback="loading...">
<TestComponent isSuspence={isSuspence} />
</Suspense>
<br />
<Footer isSuspence={isSuspence} setIsSuspence={SetIsSuspence} />
</>
);
}
export default App;
TestComponent.tsx
import { useEffect, useLayoutEffect } from "react";
function sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
export function TestComponent({ isSuspence }: { isSuspence: boolean }) {
useEffect(() => {
console.log("useEffect:callback");
return () => {
console.log("useEffect:clean up");
};
}, []);
useLayoutEffect(() => {
console.log("useLayoutEffect:callback");
return () => {
console.log("useLayoutEffect:clean up");
};
}, []);
if (isSuspence) {
throw sleep(3000);
} else {
return <button>button</button>;
}
}
Footer.tsx
import { Dispatch, SetStateAction } from "react";
export function Footer({
isSuspence,
setIsSuspence,
}: {
isSuspence: boolean;
setIsSuspence: Dispatch<SetStateAction<boolean>>;
}) {
const handleClick = () => {
setIsSuspence(!isSuspence);
};
return (
<button onClick={handleClick}>
{'Suspenceを' + (!isSuspence) + 'へ'}
</button>
);
}
よく調べてみると公式サイトに記載があった
useEffectとuseLayoutEffectの記事では見つけられませんでしたが、
Suspenceの記事に記載がありました。
最後に
同じ現象に陥った人の助けになればと思います。
ここまで読んでいただきありがとうございました。