Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 113 additions & 0 deletions week-04/진혁.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,3 +199,116 @@ const root = hydrateRoot(domNode, reactNode, {
identifierPrefix: 'react-app1',
});
```

# useLayoutEffect
useLayoutEffect는 브라우저가 화면을 그리기 전에 실행되는 useEffect의 다른 버전
- useEffect는 성능 저하가 생길수있으니 되도록 useEffect를 사용
```javascript
useLayoutEffect(setup, dependencies?)
```

## Reference
브라우저가 화면을 다시 그리기 전에 레이아웃 측정이 필요할 때 useLayoutEffect 호출
```javascript
function Tooltip() {
const ref = useRef(null);
const [tooltipHeight, setTooltipHeight] = useState(0);

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

## Parameters
- setup :
- Effect 로직 함수
- 선택적으로 cleanup 함수를 반환
- 컴포넌트가 커밋되기 전에 실행
- 의존성이 변경되면 이전값으로 cleanup -> 새 값으로 setup
- 컴포넌트가 DOM에서 제거되기 전에 cleanup 실행
- optional dependencies? :
- setup 에서 사용하는 모든 반응형값의 리스트
- object.is로 이전 값과 비교
- 생략시 컴포넌트가 커밋될때마다 실행

## Returns
undefined 반환

## Caveats
- 컴포넌트 최상위에서 호출
- Strict Mode 에서는 첫 setup 실행전에 개발환경에서 setup -> cleanup을 한번 실행
- 의존성에 객체나 함수가 있으면 불필요한 재실행 위험이 있음
- Effect는 클라이언트에서만 실행
- useLayoutEffect 안의 코드, state 업데이트는 브라우저 화면을 그리는걸 차단
- 과도하게 사용시 성능 저하
- 가능하면 useEffect를 사용
- useLayoutEffect 안에서 state를 업데이트하면 남아있는 모든 Effect를 즉시 실행

## Usage
### 브라우저가 그리기 전에 레이아웃 측정하기
대부분 컴포넌트는 :
1. JSX 반환
2. 브라우저가 위치/크기 계산
3. 화면 그리기

툴팁처럼 위치를 결정하려면 실제 크기를 알아야 하는 경우
-> 위에 공간이 없으면 아래 등 다른 위치에 표시해야 하는 경우

2-pass 렌더링 :
1. 툴팁을 임시 위치로 렌더링
2. 실제 높이 측정, 툴팁의 위치 결정
3. 툴팁을 올바른 위치로 다시 렌더링
모든 과정이 브라우저가 화면을 그리기 전에 실행되어야함
-> useLayEffect 사용

```javascript
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. tooptipHeight = 0 상태로 렌더링
2. DOM에 반영, useLayoutEffect 실행
3. useEffect에서 height 측정 -> 즉시 리렌더링
4. 툴팁이 올바른 위치에 렌더링
5. React가 DOM을 업데이트, 브라우저가 툴팁을 화면에 보여줌
- 툴팁은 2 passes 로 렌더링 ( 임시값 0, 실제 계산된 값)
- 사용자는 최종 결과만 확인

### useLayoutEffect vs useEffect
useLayoutEffect
- 브라우저 그리기 (repaint) 차단
- 레이아웃 측정 -> 즉시 반영
- 성능 부담 큼
-
useEffect
- 브라우저 그리기 (repaint) 이후 실행
- 중간 상태가 화면에 나타남
- 성능 부담 적음

## Troubleshooting
“useLayoutEffect does nothing on the server” 에러
- 서버에는 레이아웃 정보가 없음
- 서버에서 DOM 크기/위치 계산 불가
- 대체적으로 레이아웃 정보가 필요한 컴포넌트는 서버에서 렌더링 할 필요 없음 (ex. 툴팁)

### 해결 방법
- useLayoutEffet 대신 useEffect 사용
- 초기 렌더링 결과를 보여주게됨
- 컴포넌트를 클라이언트 전용으로 처리
- 서버 렌더링중에 가까운 <Suspense> 의 fallback으로 처리
- useLayoutEffect를 사용한는 컴포넌트를 hydration 이후에 렌더링
- isMounted 를 state로 활용
- hydration 중에는 useLayoutEffect를 사용하지 않는 FallbackContent
- hydration 이후에 RealContent 렌더링
- 외부 데이터에 동기화 목적일 때
- useSyncExternalStore 사용 고려
- SSR 지원