落とし穴

useLayoutEffect γ―γƒ‘γƒ•γ‚©γƒΌγƒžγƒ³γ‚Ήγ‚’δ½ŽδΈ‹γ•γ›γ‚‹ε―θƒ½ζ€§γŒγ‚γ‚ŠγΎγ™γ€‚ε―θƒ½γͺι™γ‚Š useEffect γ‚’δ½Ώη”¨γ™γ‚‹γ“γ¨γ‚’ζŽ¨ε₯¨γ—ます。

useLayoutEffect は useEffect οΏ½?δΈ€οΏ½?γ§γ™γŒγ€γƒ–γƒ©γ‚¦γ‚ΆγŒη”»ι’γ‚’ε†ζη”»γ™γ‚‹ε‰γ«οΏ½?οΏ½θ‘Œγ•γ‚ŒγΎγ™γ€‚

useLayoutEffect(setup, dependencies?)

γƒͺフゑレンス

useLayoutEffect(setup, dependencies?)

γƒ–γƒ©γ‚¦γ‚ΆγŒη”»ι’γ‚’ε†ζη”»γ™γ‚‹ε‰γ«γƒ¬γ‚€γ‚’γ‚¦γƒˆοΏ½?θ¨ˆζΈ¬γ‚’θ‘Œγ†γŸγ‚γ« useLayoutEffect を呼び出します。

import { useState, useRef, useLayoutEffect } from 'react';

function Tooltip() {
const ref = useRef(null);
const [tooltipHeight, setTooltipHeight] = useState(0);

useLayoutEffect(() => {
const { height } = ref.current.getBoundingClientRect();
setTooltipHeight(height);
}, []);
// ...

さらに例を見る

εΌ•ζ•°

  • setup: γ‚¨γƒ•γ‚§γ‚―γƒˆοΏ½?γƒ­γ‚Έγƒƒγ‚―γŒθ¨˜θΏ°γ•γ‚ŒγŸι–’ζ•°γ§γ™γ€‚γ“οΏ½?γ‚»γƒƒγƒˆγ‚’γƒƒγƒ—ι–’ζ•°γ―γ€γ‚ͺプションでクγƒͺγƒΌγƒ³γ‚’γƒƒγƒ—ι–’ζ•°γ‚’θΏ”γ™γ“γ¨γŒγ§γγΎγ™γ€‚γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγŒεˆγ‚γ¦ DOM γ«θΏ½εŠ γ•γ‚Œγ‚‹γ¨γ€React γ―γ‚»γƒƒγƒˆγ‚’γƒƒγƒ—ι–’ζ•°γ‚’οΏ½?οΏ½θ‘Œγ—γΎγ™γ€‚δΎε­˜ι…εˆ— (dependencies) γŒε€‰ζ›΄γ•γ‚ŒγŸε†γƒ¬γƒ³γƒ€γƒΌζ™‚γ«γ―γ€React γ―γΎγšε€γ„ε€€γ‚’δ½Ώγ£γ¦γ‚―γƒͺγƒΌγƒ³γ‚’γƒƒγƒ—ι–’ζ•°οΌˆγ‚γ‚Œγ°οΌ‰γ‚’οΏ½?οΏ½θ‘Œγ—γ€ζ¬‘γ«ζ–°γ—γ„ε€€γ‚’δ½Ώγ£γ¦γ‚»γƒƒγƒˆγ‚’γƒƒγƒ—ι–’ζ•°γ‚’οΏ½?οΏ½θ‘Œγ—γΎγ™γ€‚γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγŒ DOM γ‹γ‚‰ε‰Šι™€γ•γ‚ŒγŸεΎŒγ€React はクγƒͺγƒΌγƒ³γ‚’γƒƒγƒ—ι–’ζ•°γ‚’ζœ€εΎŒγ«γ‚‚γ†δΈ€εΊ¦οΏ½?οΏ½θ‘Œγ—γΎγ™γ€‚

  • 省η•₯可能 dependencies: setup γ‚³γƒΌγƒ‰ε†…γ§ε‚η…§γ•γ‚Œγ‚‹γ™γΉγ¦οΏ½?γƒͺをクティブγͺε€€οΏ½?γƒͺγ‚Ήγƒˆγ§γ™γ€‚γƒͺをクティブγͺ倀には、props、stateγ€γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆζœ¬δ½“γ«η›΄ζŽ₯οΏ½?οΏ½θ¨€γ•γ‚ŒγŸγ™γΉγ¦οΏ½?ε€‰ζ•°γŠγ‚ˆγ³ι–’ζ•°γŒε«γΎγ‚ŒγΎγ™γ€‚γƒͺγƒ³γ‚ΏγŒ React 用に設�?οΏ½γ•γ‚Œγ¦γ„γ‚‹ε ΄εˆγ€γ™γΉγ¦οΏ½?γƒͺをクティブγͺε€€γŒδΎε­˜ε€€γ¨γ—γ¦ζ­£γ—γζŒ‡οΏ½?οΏ½γ•γ‚Œγ¦γ„γ‚‹γ‹η’Ίθͺγ§γγΎγ™γ€‚δΎε­˜ε€€οΏ½?γƒͺγ‚Ήγƒˆγ―θ¦η΄ ζ•°γŒδΈ€οΏ½?οΏ½γ§γ‚γ‚‹εΏ…θ¦γŒγ‚γ‚Šγ€[dep1, dep2, dep3] οΏ½?γ‚ˆγ†γ«γ‚€γƒ³γƒ©γ‚€γƒ³γ§θ¨˜θΏ°γ™γ‚‹εΏ…θ¦γŒγ‚γ‚ŠγΎγ™γ€‚React は、Object.is γ‚’δ½Ώγ£γŸζ―”θΌƒγ§γ€γγ‚Œγžγ‚ŒοΏ½?δΎε­˜ε€€γ‚’δ»₯前�?倀と比較します。こ�?εΌ•ζ•°γ‚’ηœη•₯γ™γ‚‹γ¨γ€γ‚¨γƒ•γ‚§γ‚―γƒˆγ―γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆοΏ½?ζ―Žε›žοΏ½?γƒ¬γƒ³γƒ€γƒΌεΎŒγ«ε†οΏ½?οΏ½θ‘Œγ•γ‚ŒγΎγ™γ€‚

θΏ”γ‚Šε€€

useLayoutEffect は undefined を返します。

注意点

  • useLayoutEffect γ―γƒ•γƒƒγ‚―γ§γ‚γ‚‹γŸγ‚γ€γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆοΏ½?γƒˆγƒƒγƒ—γƒ¬γƒ™γƒ«γ‚„γ‚«γ‚Ήγ‚Ώγƒ γƒ•γƒƒγ‚―ε†…γ§οΏ½?γΏε‘Όγ³ε‡Ίγ™γ“γ¨γŒγ§γγΎγ™γ€‚γƒ«γƒΌγƒ—γ‚„ζ‘δ»Άζ–‡οΏ½?δΈ­γ§ε‘Όγ³ε‡Ίγ™γ“γ¨γ―γ§γγΎγ›γ‚“γ€‚γ“γ‚ŒγŒεΏ…θ¦γͺε ΄εˆγ―γ€ζ–°γ—γ„γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγ‚’ζŠ½ε‡Ίγ—γ€γοΏ½?δΈ­γ«γ‚¨γƒ•γ‚§γ‚―γƒˆγ‚’η§»ε‹•γ•γ›γ¦γγ γ•γ„γ€‚

  • Strict Mode γŒζœ‰εŠΉγͺε ΄εˆγ€React γ―ζœ¬η‰©οΏ½?γ‚»γƒƒγƒˆγ‚’γƒƒγƒ—οΏ½?前に、開発時専用�?γ‚»γƒƒγƒˆγ‚’γƒƒγƒ—+γ‚―γƒͺーンをップァむクルを 1 ε›žθΏ½εŠ γ§οΏ½?οΏ½θ‘Œγ—γΎγ™γ€‚γ“γ‚Œγ―γ€γ‚―γƒͺγƒΌγƒ³γ‚’γƒƒγƒ—γƒ­γ‚Έγƒƒγ‚―γŒγ‚»γƒƒγƒˆγ‚’γƒƒγƒ—γƒ­γ‚Έγƒƒγ‚―γ¨ι‘οΏ½?γ‚ˆγ†γ«ε―ΎεΏœγ—γ¦γŠγ‚Šγ€γ‚»γƒƒγƒˆγ‚’γƒƒγƒ—γ§θ‘Œγ‚γ‚ŒγŸγ“γ¨γ‚’εœζ­’γΎγŸγ―ε…ƒγ«ζˆ»γ—γ¦γ„γ‚‹γ“γ¨γ‚’δΏθ¨Όγ™γ‚‹γŸγ‚οΏ½?γ‚Ήγƒˆγƒ¬γ‚Ήγƒ†γ‚Ήγƒˆγ§γ™γ€‚ε•ι‘ŒγŒη™Ίη”Ÿγ—γŸε ΄εˆγ―γ€γ‚―γƒͺーンをップ閒数を�?�装します。

  • δΎε­˜ι…εˆ—οΏ½?δΈ€ιƒ¨γ«γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆε†…γ§οΏ½?οΏ½ηΎ©γ•γ‚ŒγŸγ‚ͺγƒ–γ‚Έγ‚§γ‚―γƒˆγ‚„ι–’ζ•°γŒγ‚γ‚‹ε ΄εˆγ€γ‚¨γƒ•γ‚§γ‚―γƒˆγŒεΏ…θ¦δ»₯δΈŠγ«ε†οΏ½?οΏ½θ‘Œγ•γ‚Œγ‚‹ε―θƒ½ζ€§γŒγ‚γ‚ŠγΎγ™γ€‚γ“γ‚Œγ‚’οΏ½?正するには、γ‚ͺγƒ–γ‚Έγ‚§γ‚―γƒˆεž‹γŠγ‚ˆγ³ι–’ζ•°εž‹οΏ½?不要γͺδΎε­˜ε€€γ‚’ε‰Šι™€γ—γΎγ™γ€‚γΎγŸγ€γ‚¨γƒ•γ‚§γ‚―γƒˆοΏ½?倖部に state οΏ½?ζ›΄ζ–°γ‚„ιžγƒͺをクティブγͺγƒ­γ‚Έγƒƒγ‚―γ‚’ζŠ½ε‡Ίγ™γ‚‹γ“γ¨γ‚‚γ§γγΎγ™γ€‚

  • γ‚¨γƒ•γ‚§γ‚―γƒˆγ―γ‚―γƒ©γ‚€γ‚’γƒ³γƒˆδΈŠγ§οΏ½?み�?οΏ½θ‘Œγ•γ‚ŒγΎγ™γ€‚γ‚΅γƒΌγƒγƒ¬γƒ³γƒ€γƒͺング中には�?οΏ½θ‘Œγ•γ‚ŒγΎγ›γ‚“γ€‚

  • useLayoutEffect ε†…οΏ½?コードと、そこでスケジγƒ₯γƒΌγƒ«γ•γ‚ŒγŸγ™γΉγ¦οΏ½? state ζ›΄ζ–°γ―γ€γƒ–γƒ©γ‚¦γ‚Άγ«γ‚ˆγ‚‹η”»ι’οΏ½?ε†ζη”»γ‚’γƒ–γƒ­γƒƒγ‚―γ—γΎγ™γ€‚ιŽεΊ¦γ«δ½Ώη”¨γ™γ‚‹γ¨γ€γ‚’γƒ—γƒͺγŒι…γγͺγ‚ŠγΎγ™γ€‚ε―θƒ½γͺι™γ‚Š useEffect を使用してください。


使用法

γƒ–γƒ©γ‚¦γ‚ΆγŒη”»ι’γ‚’ε†ζη”»γ™γ‚‹ε‰γ«γƒ¬γ‚€γ‚’γ‚¦γƒˆγ‚’ζΈ¬οΏ½?�する

ほとんど�?γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγ―γ€δ½•γ‚’γƒ¬γƒ³γƒ€γƒΌγ™γ‚‹γ‹γ‚’ζ±ΊοΏ½?οΏ½γ™γ‚‹γŸγ‚γ«γ€η”»ι’δΈŠγ§οΏ½?位�?γ‚„γ‚΅γ‚€γ‚Ίγ‚’ηŸ₯γ‚‹εΏ…θ¦γ―γ‚γ‚ŠγΎγ›γ‚“γ€‚ε˜γ« JSX を返します。そ�?εΎŒγ€γƒ–γƒ©γ‚¦γ‚ΆγŒγοΏ½?γƒ¬γ‚€γ‚’γ‚¦γƒˆοΌˆδ½οΏ½?γ¨γ‚΅γ‚€γ‚ΊοΌ‰γ‚’θ¨ˆοΏ½?�し、画青を再描画します。

γ—γ‹γ—γ€γγ‚Œγ γ‘γ§γ―δΈεεˆ†γͺε ΄εˆγ‚‚γ‚γ‚ŠγΎγ™γ€‚δΎ‹γˆγ°γ€γ‚γ‚‹θ¦η΄ γ‚’γƒ›γƒγƒΌγ—γŸγ¨γγ«θΏ‘γγ«θ‘¨η€Ίγ•γ‚Œγ‚‹γƒ„γƒΌγƒ«γƒγƒƒγƒ—γ‚’ζƒ³εƒγ—γ¦γΏγ¦γγ γ•γ„γ€‚εεˆ†γͺγ‚ΉγƒšγƒΌγ‚ΉγŒγ‚γ‚‹ε ΄εˆγ€γƒ„γƒΌγƒ«γƒγƒƒγƒ—γ―θ¦η΄ οΏ½?δΈŠγ«θ‘¨η€Ίγ•γ‚Œγ‚‹γΉγγ§γ™γŒγ€εŽγΎγ‚‰γͺγ„ε ΄εˆγ―δΈ‹γ«θ‘¨η€Ίγ•γ‚Œγ‚‹γ¨γ—γΎγ™γ€‚γƒ„γƒΌγƒ«γƒγƒƒγƒ—γ‚’ζ­£γ—γ„ζœ€η΅‚δ½οΏ½?γ«γƒ¬γƒ³γƒ€γƒΌγ™γ‚‹γŸγ‚γ«γ―γ€γοΏ½?ι«˜γ•οΌˆγ€γΎγ‚Šγ€δΈŠιƒ¨γ«εŽγΎγ‚‹γ‹γ©γ†γ‹οΌ‰γ‚’ηŸ₯γ‚‹εΏ…θ¦γŒγ‚γ‚ŠγΎγ™γ€‚

γ“γ‚Œγ‚’θ‘Œγ†γ«γ―γ€2 γƒ‘γ‚Ήγ§γƒ¬γƒ³γƒ€γƒΌγ‚’θ‘Œγ†εΏ…θ¦γŒγ‚γ‚ŠγΎγ™οΌš

  1. γƒ„γƒΌγƒ«γƒγƒƒγƒ—γ‚’οΌˆδ½οΏ½?γŒι–“ι•γ£γ¦γ„γ¦γ‚‚θ‰―γ„οΏ½?で)どこかにレンダーします。
  2. ツールチップ�?ι«˜γ•γ‚’ζΈ¬οΏ½?�し、ツールチップを配�?する場所を決�?�します。
  3. ツールチップを正しい場所で再度レンダーします。

γ“γ‚Œγ‚‰γ™γΉγ¦γ―γ€γƒ–γƒ©γ‚¦γ‚ΆγŒη”»ι’γ‚’ε†ζη”»γ™γ‚‹ε‰γ«θ‘Œγ‚γͺγ‘γ‚Œγ°γͺγ‚ŠγΎγ›γ‚“γ€‚γƒ¦γƒΌγ‚Άγ«γƒ„γƒΌγƒ«γƒγƒƒγƒ—γŒη§»ε‹•γ™γ‚‹οΏ½?γ‚’θ¦‹γ›γŸγγͺい�?γ§γ™γ€‚γƒ–γƒ©γ‚¦γ‚ΆγŒη”»ι’γ‚’ε†ζη”»γ™γ‚‹ε‰γ«γƒ¬γ‚€γ‚’γ‚¦γƒˆοΏ½?ζΈ¬οΏ½?οΏ½γ‚’θ‘Œγ†γŸγ‚γ« useLayoutEffect を呼び出します。

function Tooltip() {
const ref = useRef(null);
const [tooltipHeight, setTooltipHeight] = useState(0); // You don't know real height yet

useLayoutEffect(() => {
const { height } = ref.current.getBoundingClientRect();
setTooltipHeight(height); // Re-render now that you know the real height
}, []);

// ...use tooltipHeight in the rendering logic below...
}

ε‹•δ½œγ‚’γ‚Ήγƒ†γƒƒγƒ—γ”γ¨γ«θͺ¬ζ˜Žγ—ます。

  1. Tooltip γ―εˆε›žγ― tooltipHeight = 0 γ§γƒ¬γƒ³γƒ€γƒΌγ•γ‚ŒγΎγ™οΌˆγοΏ½?γŸγ‚γ€γƒ„γƒΌγƒ«γƒγƒƒγƒ—γ―ι–“ι•γ£γŸδ½οΏ½?に配�?γ•γ‚Œγ‚‹ε―θƒ½ζ€§γŒγ‚γ‚ŠγΎγ™οΌ‰γ€‚
  2. React γ―γγ‚Œγ‚’ DOM に配�?し、useLayoutEffect οΏ½?コードを�?οΏ½θ‘Œγ—γΎγ™γ€‚
  3. useLayoutEffect はツールチップ�?ε†…οΏ½?οΏ½οΏ½?ι«˜γ•γ‚’ζΈ¬οΏ½?�し、即時�?ε†γƒ¬γƒ³γƒ€γƒΌγ‚’γƒˆγƒͺガします。
  4. Tooltip は�?οΏ½ιš›οΏ½? tooltipHeight γ§ε†εΊ¦γƒ¬γƒ³γƒ€γƒΌγ•γ‚ŒγΎγ™οΌˆγƒ„γƒΌγƒ«γƒγƒƒγƒ—γŒζ­£γ—γι…οΏ½?γ•γ‚ŒγΎγ™οΌ‰γ€‚
  5. React が DOM δΈŠγ§ζ›΄ζ–°γ‚’θ‘Œγ„γ€ζœ€η΅‚ηš„γ«γƒ–γƒ©γ‚¦γ‚ΆγŒγƒ„γƒΌγƒ«γƒγƒƒγƒ—γ‚’θ‘¨η€Ίγ—γΎγ™γ€‚

δ»₯δΈ‹οΏ½?γƒœγ‚Ώγƒ³γ«γƒ›γƒγƒΌγ—γ¦γΏγ¦γ€γƒ„γƒΌγƒ«γƒγƒƒγƒ—γŒεŽγΎγ‚‹γ‹γ©γ†γ‹γ«εΏœγ˜γ¦δ½οΏ½?γ‚’θͺΏζ•΄γ™γ‚‹ζ§˜ε­γ‚’θ¦³ε―Ÿγ—γ¦γγ γ•γ„γ€‚

import { useRef, useLayoutEffect, useState } from 'react';
import { createPortal } from 'react-dom';
import TooltipContainer from './TooltipContainer.js';

export default function Tooltip({ children, targetRect }) {
  const ref = useRef(null);
  const [tooltipHeight, setTooltipHeight] = useState(0);

  useLayoutEffect(() => {
    const { height } = ref.current.getBoundingClientRect();
    setTooltipHeight(height);
    console.log('Measured tooltip height: ' + height);
  }, []);

  let tooltipX = 0;
  let tooltipY = 0;
  if (targetRect !== null) {
    tooltipX = targetRect.left;
    tooltipY = targetRect.top - tooltipHeight;
    if (tooltipY < 0) {
      // It doesn't fit above, so place below.
      tooltipY = targetRect.bottom;
    }
  }

  return createPortal(
    <TooltipContainer x={tooltipX} y={tooltipY} contentRef={ref}>
      {children}
    </TooltipContainer>,
    document.body
  );
}

Tooltip γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγ‚’ 2 γƒ‘γ‚Ήγ§οΌˆεˆε›žγ― tooltipHeight が 0 で、2 ε›žοΏ½?は�?οΏ½ιš›γ«ζΈ¬οΏ½?οΏ½γ—γŸι«˜γ•γ§οΌ‰γƒ¬γƒ³γƒ€γƒΌγ™γ‚‹εΏ…θ¦γŒγ‚γ‚‹γ«γ‚‚γ‹γ‹γ‚γ‚‰γšγ€ζœ€η΅‚η΅ζžœγ γ‘γŒθ‘¨η€Ίγ•γ‚Œγ‚‹γ“γ¨γ«ζ³¨οΏ½?γ—γ¦γγ γ•γ„γ€‚γ“γ‚ŒγŒγ€γ“οΏ½?例で useEffect οΏ½?δ»£γ‚γ‚Šγ« useLayoutEffect γŒεΏ…θ¦γͺ理由です。詳細γͺ違いはδ»₯δΈ‹οΏ½?ι€šγ‚Šγ§γ™γ€‚

useLayoutEffect vs useEffect

δΎ‹ 1/2:
useLayoutEffect はブラウア�?再描画をブロックする

React は、useLayoutEffect ε†…οΏ½?コードとそ�?中でスケジγƒ₯γƒΌγƒ«γ•γ‚ŒγŸγ™γΉγ¦οΏ½? state ζ›΄ζ–°γŒγ€γƒ–γƒ©γ‚¦γ‚ΆγŒη”»ι’γ‚’ε†ζη”»γ™γ‚‹ε‰γ«ε‡¦η†γ•γ‚Œγ‚‹γ“γ¨γ‚’δΏθ¨Όγ—γΎγ™γ€‚γ“γ‚Œγ«γ‚ˆγ‚Šγ€γƒ„γƒΌγƒ«γƒγƒƒγƒ—γ‚’γƒ¬γƒ³γƒ€γƒΌγ—γ€ζΈ¬οΏ½?οΏ½γ—γ€ε†εΊ¦γƒ¬γƒ³γƒ€γƒΌγ™γ‚‹γ¨γ„γ†ε‡¦η†γ‚’γ€γƒ¦γƒΌγ‚ΆγŒζœ€εˆοΏ½?δ½™εˆ†γͺγƒ¬γƒ³γƒ€γƒΌγ«ζ°—δ»˜γ‹γͺγ„γ‚ˆγ†γ«θ‘Œγ†γ“γ¨γŒγ§γγΎγ™γ€‚θ¨€γ„ζ›γˆγ‚‹γ¨γ€useLayoutEffect はブラウア�?描画をブロックします。

import { useRef, useLayoutEffect, useState } from 'react';
import { createPortal } from 'react-dom';
import TooltipContainer from './TooltipContainer.js';

export default function Tooltip({ children, targetRect }) {
  const ref = useRef(null);
  const [tooltipHeight, setTooltipHeight] = useState(0);

  useLayoutEffect(() => {
    const { height } = ref.current.getBoundingClientRect();
    setTooltipHeight(height);
  }, []);

  let tooltipX = 0;
  let tooltipY = 0;
  if (targetRect !== null) {
    tooltipX = targetRect.left;
    tooltipY = targetRect.top - tooltipHeight;
    if (tooltipY < 0) {
      // It doesn't fit above, so place below.
      tooltipY = targetRect.bottom;
    }
  }

  return createPortal(
    <TooltipContainer x={tooltipX} y={tooltipY} contentRef={ref}>
      {children}
    </TooltipContainer>,
    document.body
  );
}

補袳

2 γƒ‘γ‚Ήγ§γƒ¬γƒ³γƒ€γƒΌγ—γ¦γƒ–γƒ©γ‚¦γ‚Άγ‚’γƒ–γƒ­γƒƒγ‚―γ™γ‚‹γ“γ¨γ―γƒ‘γƒ•γ‚©γƒΌγƒžγƒ³γ‚Ήγ‚’δ½ŽδΈ‹γ•γ›γΎγ™γ€‚γ§γγ‚‹ι™γ‚ŠιΏγ‘γ¦γγ γ•γ„γ€‚


γƒˆγƒ©γƒ–γƒ«γ‚·γƒ₯ーティング

”useLayoutEffect does nothing on the server” γ¨γ„γ†γ‚¨γƒ©γƒΌγŒε‡Ίγ‚‹

useLayoutEffect οΏ½?οΏ½?ηš„γ―γ€γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγŒγƒ¬γƒ³γƒ€γƒΌοΏ½?γŸγ‚γ«γƒ¬γ‚€γ‚’γ‚¦γƒˆζƒ…ε ±γ‚’δ½Ώη”¨γ§γγ‚‹γ‚ˆγ†γ«γ™γ‚‹γ“γ¨γ§γ™γ€‚

  1. εˆζœŸγ‚³γƒ³γƒ†γƒ³γƒ„γ‚’γƒ¬γƒ³γƒ€γƒΌγ™γ‚‹γ€‚
  2. γƒ–γƒ©γ‚¦γ‚ΆγŒη”»ι’γ‚’ε†ζη”»γ™γ‚‹ε‰γ«γƒ¬γ‚€γ‚’γ‚¦γƒˆγ‚’ζΈ¬οΏ½?�する。
  3. θͺ­γΏε–γ£γŸγƒ¬γ‚€γ‚’γ‚¦γƒˆζƒ…ε ±γ‚’δ½Ώη”¨γ—γ¦ζœ€η΅‚γ‚³γƒ³γƒ†γƒ³γƒ„γ‚’γƒ¬γƒ³γƒ€γƒΌγ™γ‚‹γ€‚

あγͺγŸγ€γΎγŸγ―γ‚γͺた�?γƒ•γƒ¬γƒΌγƒ γƒ―γƒΌγ‚―γŒγ‚΅γƒΌγƒγƒ¬γƒ³γƒ€γƒͺγƒ³γ‚°γ‚’δ½Ώη”¨γ—γ¦γ„γ‚‹ε ΄εˆγ€React γ‚’γƒ—γƒͺは初期葨瀺�?γŸγ‚γ«γ‚΅γƒΌγƒδΈŠγ§ HTML γ«γƒ¬γƒ³γƒ€γƒΌγ•γ‚ŒγΎγ™γ€‚γ“γ‚Œγ«γ‚ˆγ‚Šγ€JavaScript γ‚³γƒΌγƒ‰γŒγƒ­γƒΌγƒ‰γ•γ‚Œγ‚‹ε‰γ«εˆζœŸ HTML を葨瀺できます。

ε•ι‘Œγ―γ€γ‚΅γƒΌγƒδΈŠγ«γ―γƒ¬γ‚€γ‚’γ‚¦γƒˆζƒ…ε ±γŒγͺいことです。

ε…ˆγ»γ©οΏ½?例では、Tooltip γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆε†…γ§οΏ½? useLayoutEffect οΏ½?ε‘Όγ³ε‡Ίγ—γ«γ‚ˆγ‚Šγ€ι«˜γ•γ«εΏœγ˜γ¦θ‡ͺ身を正しくコンテンツ�?δΈŠγΎγŸγ―δΈ‹γ«ι…οΏ½?γ™γ‚‹γ“γ¨γŒγ§γγ¦γ„γΎγ—γŸγ€‚εˆζœŸοΏ½?ァーバ HTML οΏ½?一部として Tooltip γ‚’γƒ¬γƒ³γƒ€γƒΌγ—γ‚ˆγ†γ¨γ™γ‚‹γ¨γ€γ“γ‚Œγ―δΈε―θƒ½γ«γͺγ‚ŠγΎγ™γ€‚γ‚΅γƒΌγƒδΈŠγ§γ―γΎγ γƒ¬γ‚€γ‚’γ‚¦γƒˆγŒε­˜εœ¨γ—γͺいからです! γ—γŸγŒγ£γ¦γ€γ‚΅γƒΌγƒδΈŠγ§γƒ¬γƒ³γƒ€γƒΌγ—γ¦γ‚‚γ€JavaScript γŒγƒ­γƒΌγƒ‰γ•γ‚ŒοΏ½?οΏ½θ‘Œγ•γ‚ŒγŸιš›γ«γ€γ‚―γƒ©γ‚€γ‚’γƒ³γƒˆδΈŠγ§δ½οΏ½?οΏ½?γ€Œγ‚Έγƒ£γƒ³γƒ—γ€γŒθ΅·γ“γ£γ¦γ—γΎγ„γΎγ™γ€‚

ι€šεΈΈγ€γƒ¬γ‚€γ‚’γ‚¦γƒˆζƒ…ε ±γ«δΎε­˜γ™γ‚‹γ‚ˆγ†γͺγ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγ―γ€γ‚΅γƒΌγƒδΈŠγ§γƒ¬γƒ³γƒ€γƒΌγ™γ‚‹εΏ…θ¦γ―γ‚γ‚ŠγΎγ›γ‚“γ€‚δΎ‹γˆγ°γ€εˆζœŸγƒ¬γƒ³γƒ€γƒΌδΈ­γ« Tooltip γ‚’θ‘¨η€Ίγ™γ‚‹γ“γ¨γ―γŠγγ‚‰γη„‘ζ„ε‘³γ§γ™γ€‚γ“γ‚Œγ―γ‚―γƒ©γ‚€γ‚’γƒ³γƒˆγ§οΏ½?γƒ¦γƒΌγ‚Άζ“δ½œγ«εΏœγ˜γ¦γƒˆγƒͺγ‚¬γ•γ‚Œγ‚‹γ‚‚οΏ½?だからです。

しかし、こ�?ε•ι‘Œγ«η›΄ι’γ—γ¦γ„γ‚‹ε ΄εˆγ€γ„γγ€γ‹οΏ½?ιΈζŠžθ‚’γŒγ‚γ‚ŠγΎγ™γ€‚

  • useLayoutEffect γ‚’ useEffect に�?γζ›γˆγΎγ™γ€‚γ“γ‚Œγ«γ‚ˆγ‚Š React γ«ε―Ύγ—γ¦γ€εˆζœŸγƒ¬γƒ³γƒ€γƒΌη΅ζžœοΏ½?θ‘¨η€Ίγ‚’ζη”»γ‚’γƒ–γƒ­γƒƒγ‚―γ›γšγ«θ‘Œγ£γ¦γ‚ˆγ„γ“γ¨γ‚’δΌγˆγΎγ™οΌˆε…ƒοΏ½? HTML γ―γ‚¨γƒ•γ‚§γ‚―γƒˆγŒοΏ½?οΏ½θ‘Œγ•γ‚Œγ‚‹ε‰γ«θ‘¨η€Ίγ•γ‚Œγ‚‹γ‹γ‚‰γ§γ™οΌ‰γ€‚

  • γ‚γ‚‹γ„γ―γ€γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγ‚’γ‚―γƒ©γ‚€γ‚’γƒ³γƒˆε°‚η”¨γ¨γ—γ¦γƒžγƒΌγ‚―γ—γΎγ™γ€‚γ“γ‚Œγ«γ‚ˆγ‚Š React に対して、ァーバレンダγƒͺγƒ³γ‚°δΈ­γ«ζœ€γ‚‚θΏ‘γ„ <Suspense> バウンダγƒͺγΎγ§γ€γ‚³γƒ³γƒ†γƒ³γƒ„γ‚’γƒ­γƒΌγƒ‰δΈ­γ¨γ„γ†γƒ•γ‚©γƒΌγƒ«γƒγƒƒγ‚―οΌˆδΎ‹γˆγ°γ€γ‚Ήγƒ”γƒŠγ‚„γ‚°γƒͺγƒžγƒΌοΌ‰γ«οΏ½?γζ›γˆγ‚‹γ‚ˆγ†γ«ζŒ‡η€Ίγ—γΎγ™γ€‚

  • あるいは、useLayoutEffect γ‚’ζŒγ€γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγ‚’γƒγ‚€γƒ‰γƒ¬γƒΌγ‚·γƒ§γƒ³οΏ½?後に�?みレンダーします。false γ«εˆζœŸεŒ–γ•γ‚ŒγŸγƒ–γƒΌγƒͺγ‚’γƒ³εž‹οΏ½? isMounted という state γ‚’δΏζŒγ—γ¦γŠγγ€useEffect οΏ½?呼び出し内で true に設�?�します。そしてレンダーロジックは return isMounted ? <RealContent /> : <FallbackContent /> οΏ½?γ‚ˆγ†γ«γ—γΎγ™γ€‚γ‚΅γƒΌγƒδΈŠγŠγ‚ˆγ³γƒγ‚€γƒ‰γƒ¬γƒΌγ‚·γƒ§γƒ³δΈ­γ―γ€γƒ¦γƒΌγ‚Άγ― useLayoutEffect を呼び出さγͺい FallbackContent を見ることにγͺγ‚ŠγΎγ™γ€‚γοΏ½?εΎŒγ€React γ―γγ‚Œγ‚’γ‚―γƒ©γ‚€γ‚’γƒ³γƒˆε°‚η”¨οΏ½? RealContent に�?γζ›γˆγΎγ™γŒγ€γγ“γ«γ― useLayoutEffect οΏ½?ε‘Όγ³ε‡Ίγ—γ‚’ε«γ‚€γ“γ¨γŒγ§γγΎγ™γ€‚

  • γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγ‚’ε€–ιƒ¨γƒ‡γƒΌγ‚Ώγ‚Ήγƒˆγ‚’γ¨εŒζœŸγ•γ›γ¦γŠγ‚Šγ€γƒ¬γ‚€γ‚’γ‚¦γƒˆζΈ¬οΏ½?�とは異γͺる理由で useLayoutEffect γ‚’δ½Ώγ£γ¦γ„γ‚‹ε ΄εˆγ€δ»£γ‚γ‚Šγ« useSyncExternalStore γ‚’ζ€œθ¨Žγ—γ¦γΏγ¦γγ γ•γ„γ€‚γ“γ‚Œγ―γ‚΅γƒΌγƒγƒ¬γƒ³γƒ€γƒͺγƒ³γ‚°γ‚’γ‚΅γƒγƒΌγƒˆγ—γ¦γ„γΎγ™γ€‚