diff --git a/README.md b/README.md
index 9f5dfcd..616eb87 100644
--- a/README.md
+++ b/README.md
@@ -46,3 +46,4 @@
| [03-1](./week-03/) | [useDebugValue](https://react.dev/reference/react/useDebugValue)
[useDeferredValue](https://react.dev/reference/react/useDeferredValue) | 2026.01.20 |
| [03-2](./week-03/) | [useEffect](https://react.dev/reference/react/useEffect) | 2026.01.23 |
| [04-1](./week-04/) | [useEffectEvent](https://react.dev/reference/react/useEffectEvent)
[useId](https://react.dev/reference/react/useId) | 2026.01.27 |
+| [04-2](./week-04/) | [useLayoutEffect](https://react.dev/reference/react/useLayoutEffect) | 2026.01.30 |
diff --git a/week-04/README.md b/week-04/README.md
index 7745742..b1abcec 100644
--- a/week-04/README.md
+++ b/week-04/README.md
@@ -2,10 +2,11 @@
## 발표자
--
+- 정상인
-
## 범위
- [useEffectEvent](https://react.dev/reference/react/useEffectEvent)
- [useId](https://react.dev/reference/react/useId)
+- [useLayoutEffect](https://react.dev/reference/react/useLayoutEffect)
diff --git "a/week-04/\354\260\270\354\206\224.md" "b/week-04/\354\260\270\354\206\224.md"
index 962eda7..e44ecbe 100644
--- "a/week-04/\354\260\270\354\206\224.md"
+++ "b/week-04/\354\260\270\354\206\224.md"
@@ -181,3 +181,53 @@ const root = hydrateRoot(domNode, reactNode, {
- Single page에 둘 이상의 React app을 render 하고, React app 중 server-rendered 되는 app이 있는 경우,
- **client에서 `hydrateRoot`에 `identifierPrefix`로 전달한 값과 server API의 `identifierPrefix`로 전달한 값이 같아야 함** (e.g. `renderToPipeableStream`)
+
+## [useLayoutEffect](https://react.dev/reference/react/useLayoutEffect)
+
+- Browser가 screen을 repaint 하기 이전에 Effect를 실행시켜 주는 hook
+- Browser repaint 이전에 layout measurements를 수행할 때 사용
+- `useEffect`와 동일하지만 실행 시점이 다르다.
+ 1. `useLayoutEffect`의 Effect 실행
+ 2. Browser painting
+ 3. Browser가 화면을 그린 뒤 `useEffect`의 Effect 실행
+- **성능에 영향을 줄 수 있으므로, 가능하면 `useEffect`를 먼저 사용한다.**
+
+### Reference
+
+- `useLayoutEffect(setup, dependencies?)`
+- Parameters
+ - `setup` : 실행할 Effect logic
+ - `dependencies?` : `setup` 내부에서 사용된 reactive values
+- Returns : `undefined`
+- Caveats
+ - `setup` 함수 내부에서 실행되는 모든 코드 및 state update는 **browser에서 screen을 repainting 하는 것을 block** 하므로, 과도하게 사용하면 app이 멈출 수 있다.
+ - `setup` 함수 내부에서 state update를 trigger 하면 React는 **`useEffect`를 포함한 모든 Effect들을 즉시 실행**한 후 re-rendering을 진행한다.
+ - Browser가 화면을 그리기 전에 모든 Effect들을 정리하고 새로운 rendering cycle을 시작하기 위해 대기중인 Effect들을 처리하는 것
+
+### Usage
+
+#### Measuring layout before the browser repaints the screen
+
+```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...
+}
+```
+
+- 대부분의 component들은 JSX를 반환하기만 하고, browser가 layout을 계산해서 repaint 해 준다.
+- Component가 render 되기 전에 size 등을 사용해서 layout을 계산해야 할 때 `useLayoutEffect` 활용 가능 (e.g. Tooltip 등)
+- 동작 순서
+ 1. `Tooltip`은 처음에 `tooltipHeight`이 0인 상태로 render 됨
+ 2. React는 `Tooltip`을 DOM에 배치한 뒤 `useLayoutEffect` 코드 실행
+ 3. `useLayoutEffect` 에서는 `Tooltip`의 height을 계산해서 state를 변경하고 re-render를 trigger
+ 4. `Tooltip`은 변경된 `tooltipHeight` 값을 사용해서 정확한 layout으로 render
+ 5. React는 DOM을 갱신하고, browser는 tooltip을 표시
+- 이 때, `tooltipHeight` 초깃값은 0 이지만 `useLayoutEffect` 내부에서 정확히 계산된 height으로 변경했기 때문에 height이 0인 상태의 `Tooltip`은 그려지지 않아서 화면에 보이지 않음
\ No newline at end of file