useLayoutEffect
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 γγΉγ§γ¬γ³γγΌγθ‘γεΏ θ¦γγγγΎγοΌ
- γγΌγ«γγγγοΌδ½οΏ½?γιιγ£γ¦γγ¦γθ―γοΏ½?γ§οΌγ©γγγ«γ¬γ³γγΌγγΎγγ
- γγΌγ«γγγοΏ½?ι«γγζΈ¬οΏ½?οΏ½γγγγΌγ«γγγγι οΏ½?γγε ΄ζγζ±ΊοΏ½?οΏ½γγΎγγ
- γγΌγ«γγγγζ£γγε ΄ζγ§εεΊ¦γ¬γ³γγΌγγΎγγ
γγγγγΉγ¦γ―γγγ©γ¦γΆγη»ι’γεζη»γγεγ«θ‘γγͺγγγ°γͺγγΎγγγγ¦γΌγΆγ«γγΌγ«γγγγη§»εγγοΏ½?γθ¦γγγγͺγοΏ½?γ§γγγγ©γ¦γΆγη»ι’γεζη»γγεγ«γ¬γ€γ’γ¦γοΏ½?ζΈ¬οΏ½?οΏ½γθ‘γγγγ« 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...
}εδ½γγΉγγγγγ¨γ«θͺ¬ζγγΎγγ
Tooltipγ―εεγ―tooltipHeight = 0γ§γ¬γ³γγΌγγγΎγοΌγοΏ½?γγγγγΌγ«γγγγ―ιιγ£γδ½οΏ½?γ«ι οΏ½?γγγε―θ½ζ§γγγγΎγοΌγ- React γ―γγγ DOM γ«ι
οΏ½?γγ
useLayoutEffectοΏ½?γ³γΌγγοΏ½?οΏ½θ‘γγΎγγ useLayoutEffectγ―γγΌγ«γγγοΏ½?ε οΏ½?οΏ½οΏ½?ι«γγζΈ¬οΏ½?οΏ½γγε³ζοΏ½?εγ¬γ³γγΌγγγͺγ¬γγΎγγTooltipγ―οΏ½?οΏ½ιοΏ½?tooltipHeightγ§εεΊ¦γ¬γ³γγΌγγγΎγοΌγγΌγ«γγγγζ£γγι οΏ½?γγγΎγοΌγ- 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 γεΏ
θ¦γͺηη±γ§γγθ©³η΄°γͺιγγ―δ»₯δΈοΏ½?ιγγ§γγ
δΎ 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 ); }
γγ©γγ«γ·γ₯γΌγγ£γ³γ°
βuseLayoutEffect does nothing on the serverβ γ¨γγγ¨γ©γΌγεΊγ
useLayoutEffect οΏ½?οΏ½?ηγ―γγ³γ³γγΌγγ³γγγ¬γ³γγΌοΏ½?γγγ«γ¬γ€γ’γ¦γζ
ε ±γδ½Ώη¨γ§γγγγγ«γγγγ¨γ§γγ
- εζγ³γ³γγ³γγγ¬γ³γγΌγγγ
- γγ©γ¦γΆγη»ι’γεζη»γγεγ«γ¬γ€γ’γ¦γγζΈ¬οΏ½?οΏ½γγγ
- θͺγΏεγ£γγ¬γ€γ’γ¦γζ ε ±γδ½Ώη¨γγ¦ζη΅γ³γ³γγ³γγγ¬γ³γγΌγγγ
γγͺγγγΎγγ―γγͺγοΏ½?γγ¬γΌγ γ―γΌγ―γγ΅γΌγγ¬γ³γγͺγ³γ°γδ½Ώη¨γγ¦γγε ΄εγ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γζ€θ¨γγ¦γΏγ¦γγ γγγγγγ―γ΅γΌγγ¬γ³γγͺγ³γ°γγ΅γγΌγγγ¦γγΎγγ