diff --git "a/week-03/\353\257\274\355\230\201.md" "b/week-03/\353\257\274\355\230\201.md"
new file mode 100644
index 0000000..ea89adf
--- /dev/null
+++ "b/week-03/\353\257\274\355\230\201.md"
@@ -0,0 +1,1022 @@
+# useState
+
+## 함수 내부에서 자체적으로 변수를 사용해 값을 변경한다면?
+
+```ts
+function Component() {
+ let state = 'hello';
+
+ function handleButtonClick() {
+ state = 'hi';
+ }
+
+ return (
+ <>
+
{state}
+
+ >
+ );
+}
+```
+
+위 코드에서 `handleButtonClick` 함수를 클릭하여도 화면 상의 `state`는 변경되지 않는다.
+**화면 상의 값이 변경되려면 리렌더링이 일어나야 하는데**, 위 코드만으로는 리렌더링이 일어나지 않는다.
+
+```ts
+const [, trigger] = useState();
+let state = 'hello';
+
+function handleButtonClick() {
+ state = 'hi';
+ trigger();
+}
+```
+
+위 코드에서는 `useState`에 의하여 리렌더링이 일어난다.
+하지만, 리렌더링이 일어나면서 `state` 값도 초기화되기 때문에, 결국 `state`는 다시 `'hello'`로 초기화된다.
+
+---
+
+## 게으른 초기화
+
+`useState`의 초기값으로 일반 값을 전달할 수도 있지만, 콜백 함수를 전달할 수도 있다.
+
+```ts
+const [state, setState] = useState(() => {
+ return 'hello';
+});
+```
+
+이 방식을 게으른 초기화라고 한다.
+
+> `useState`의 초기값에 콜백 함수를 통해 반환값을 전달하면, 리렌더링 되어도 `state` 값이 유지된다.
+즉, 리렌더링이 발생해도 콜백 함수는 다시 실행되지 않으며, `React`가 저장해둔 `state` 변경되지 않는다.
+
+---
+
+### 어떤 경우에 게으른 초기화를 하면 좋을까?
+
+게으른 초기화는 초기값을 계산하는 비용이 큰 경우 유용하다.
+예를 들어, `localStorage`에서 값을 가져오거나, `map`처럼 배열에 대한 접근, `JSON.parse`를 수행하는 경우에 사용할 수 있다.
+
+```ts
+const [value, setValue] = useState(() => {
+ return localStorage.getItem('value') ?? 'default';
+});
+```
+
+이렇게 작성하면 `localStorage`에서 값을 가져오는 작업은 초기 렌더링 때만 실행되고, 이후 리렌더링에서는 기존 `state` 값이 유지된다.
+
+---
+
+# useEffect
+
+## useEffect란?
+
+`useEffect`는 컴포넌트가 렌더링된 이후 특정 작업, 즉 **부수 효과(Side Effect)**를 처리하기 위해 사용하는 React Hook이다.
+
+대표적인 부수 효과에는 다음과 같은 작업이 있다.
+
+- API 요청
+- 이벤트 리스너 등록
+- 타이머 실행
+- 외부 라이브러리 연동
+- DOM 직접 조작
+
+```tsx
+useEffect(() => {
+ // 첫 번째 인수: 실행할 콜백 함수
+ console.log('컴포넌트가 처음 렌더링될 때 실행된다.');
+}, []); // 두 번째 인수: 의존성 배열
+```
+
+`useEffect`는 두 개의 인수를 받는다.
+
+1. 첫 번째 인수: 실행할 콜백 함수
+2. 두 번째 인수: 의존성 배열
+
+의존성 배열에 빈 배열 `[]`을 넣으면 컴포넌트가 **처음 마운트될 때만** 실행된다.
+
+---
+
+## useEffect의 마운트와 언마운트
+
+### 마운트(mount)란?
+
+> 💡 컴포넌트가 처음 생성되고, 실제 브라우저 DOM에 삽입되어 화면에 나타나는 과정
+
+즉, 컴포넌트가 화면에 처음 등장하는 시점을 의미한다.
+
+### 언마운트(unmount)란?
+
+> 💡 컴포넌트가 화면에서 제거되고, DOM에서도 사라지는 과정
+
+즉, 컴포넌트가 더 이상 화면에 표시되지 않는 시점을 의미한다.
+
+```tsx
+useEffect(() => {
+ // 컴포넌트가 마운트될 때 실행된다.
+
+ return () => {
+ // 컴포넌트가 언마운트될 때 실행된다.
+ };
+}, []); // 의존성 배열
+```
+
+위 코드에서 `useEffect`의 콜백 함수는 컴포넌트가 마운트될 때 실행된다.
+
+그리고 `return` 안의 함수는 컴포넌트가 언마운트될 때 실행된다. 이 함수를 **클린업 함수**라고 한다.
+
+---
+
+## 클린업 함수
+
+클린업 함수는 `useEffect` 내부에서 `return`하는 함수다.
+
+> 💡 컴포넌트가 언마운트될 때, 또는 effect가 다시 실행되기 전에 이전 effect를 정리하기 위해 사용된다.
+
+```tsx
+useEffect(() => {
+ const timerId = setInterval(() => {
+ console.log('1초마다 실행된다.');
+ }, 1000);
+
+ // 클린업 함수
+ return () => {
+ clearInterval(timerId);
+ console.log('Cleanup: Timer cleared');
+ };
+}, []);
+```
+
+위 코드는 컴포넌트가 마운트되면 `setInterval`을 실행한다.
+
+그리고 컴포넌트가 언마운트되면 클린업 함수에서 `clearInterval`을 실행하여 타이머를 정리한다.
+
+빈 의존성 배열 `[]`을 전달했기 때문에 effect는 컴포넌트가 마운트될 때 실행되고, 클린업 함수는 언마운트될 때 실행된다.
+
+---
+
+## 클린업 함수를 사용하지 않으면 발생할 수 있는 문제
+
+`useEffect` 안에서 이벤트 리스너, 타이머, 구독과 같은 작업을 실행했다면 컴포넌트가 사라질 때 해당 작업을 정리해야 한다.
+
+클린업 함수를 사용하지 않으면 컴포넌트가 언마운트된 이후에도 이전에 등록한 작업이 계속 남아 있을 수 있다.
+
+### 1. 메모리 누수
+
+컴포넌트가 화면에서 사라졌는데도 이벤트 리스너나 타이머가 계속 실행되면 불필요한 메모리를 계속 사용하게 된다.
+
+예를 들어 `setInterval`을 사용하고 클린업 함수에서 제거하지 않으면, 컴포넌트가 사라진 뒤에도 타이머가 계속 동작할 수 있다.
+
+```tsx
+useEffect(() => {
+ const timerId = setInterval(() => {
+ console.log('타이머 실행');
+ }, 1000);
+
+ return () => {
+ clearInterval(timerId);
+ };
+}, []);
+```
+
+### 2. 예상치 못한 동작
+
+클린업을 하지 않으면 이전에 등록된 이벤트나 타이머가 중복으로 실행될 수 있다.
+
+예를 들어 버튼 클릭 이벤트를 등록했는데 컴포넌트가 다시 렌더링될 때마다 이벤트가 계속 추가된다면, 한 번 클릭했을 뿐인데 같은 함수가 여러 번 실행될 수 있다.
+
+```tsx
+useEffect(() => {
+ const handleClick = () => {
+ console.log('클릭됨');
+ };
+
+ window.addEventListener('click', handleClick);
+
+ return () => {
+ window.removeEventListener('click', handleClick);
+ };
+}, []);
+```
+
+이처럼 `useEffect`에서 외부에 영향을 주는 작업을 했다면 클린업 함수를 통해 정리하는 것이 좋다.
+
+---
+
+## 의존성 배열이 없는 useEffect
+
+```tsx
+useEffect(() => {
+ console.log('렌더링될 때마다 실행된다.');
+});
+```
+
+의존성 배열을 전달하지 않은 `useEffect`는 컴포넌트가 렌더링될 때마다 실행된다.
+
+그렇다면 다음과 같은 의문이 생길 수 있다.
+
+> ❓ 의존성 배열이 없는 `useEffect`가 매 렌더링마다 실행된다면, 굳이 `useEffect`를 사용할 필요가 있을까?
+
+결론부터 말하면, 필요하다.
+
+`useEffect`는 컴포넌트의 렌더링이 완료된 이후에 실행된다. 즉, 화면을 그리는 작업이 끝난 뒤 부수 효과를 처리한다.
+
+반면 컴포넌트 함수 내부에 코드를 직접 작성하면, 해당 코드는 렌더링 과정 중에 실행된다.
+
+```tsx
+function Example() {
+ console.log('렌더링 중 실행된다.');
+
+ return
Example
;
+}
+```
+
+위 코드는 컴포넌트가 렌더링되는 도중 실행된다.
+
+만약 이 위치에서 무거운 작업을 실행하면 컴포넌트가 JSX를 반환하는 시점이 늦어질 수 있다. 결과적으로 화면 렌더링을 방해하고 성능에 악영향을 줄 수 있다.
+
+반면 `useEffect` 안에 작성한 코드는 렌더링이 끝난 이후 실행된다.
+
+```tsx
+function Example() {
+ useEffect(() => {
+ console.log('렌더링 이후 실행된다.');
+ });
+
+ return
Example
;
+}
+```
+
+따라서 렌더링 결과에 직접 영향을 주지 않는 작업은 컴포넌트 내부에 바로 작성하기보다 `useEffect` 안에서 처리하는 것이 적절하다.
+
+---
+
+```tsx
+useEffect(() => {
+ // 매 렌더링 후 실행
+});
+
+useEffect(() => {
+ // 처음 마운트될 때만 실행
+}, []);
+
+useEffect(() => {
+ // count가 변경될 때 실행
+}, [count]);
+```
+
+---
+
+# useMemo
+
+## useMemo란?
+
+`useMemo`는 계산 결과를 메모이제이션하기 위해 사용하는 React Hook이다.
+
+> 💡 메모이제이션이란, 이전에 계산한 값을 저장해두고 같은 조건에서는 다시 계산하지 않고 저장된 값을 재사용하는 기법이다.
+
+React 컴포넌트는 상태(state)나 props가 변경되면 다시 렌더링된다.
+
+이때 컴포넌트 내부의 변수나 함수도 다시 실행된다. 만약 컴포넌트 안에서 무거운 계산을 하고 있다면, 렌더링될 때마다 같은 계산이 반복되어 성능에 영향을 줄 수 있다.
+
+`useMemo`는 이런 불필요한 계산을 줄이기 위해 사용한다.
+
+```tsx
+const memoizedValue = useMemo(() => {
+ // 첫 번째 인수: 값을 계산하는 콜백 함수
+ return expensiveCalculation();
+}, []); // 두 번째 인수: 의존성 배열
+```
+
+`useMemo`는 두 개의 인수를 받는다.
+
+1. 첫 번째 인수: 값을 계산해서 반환하는 콜백 함수
+2. 두 번째 인수: 의존성 배열
+
+의존성 배열의 값이 변경되지 않으면, 이전에 계산한 값을 재사용한다.
+
+---
+
+## useMemo 기본 예시
+
+```tsx
+import { useMemo, useState } from 'react';
+
+function Example() {
+ const [count, setCount] = useState(0);
+ const [text, setText] = useState('');
+
+ const doubledCount = useMemo(() => {
+ console.log('count 계산 실행');
+ return count * 2;
+ }, [count]);
+
+ return (
+
+ );
+}
+```
+
+위 코드에서 `doubledCount`는 `count` 값을 기준으로 계산된다.
+
+```tsx
+const doubledCount = useMemo(() => {
+ console.log('count 계산 실행');
+ return count * 2;
+}, [count]);
+```
+
+의존성 배열에 `[count]`가 들어 있기 때문에 `count`가 변경될 때만 다시 계산된다.
+
+반대로 `text` 값이 변경되어 컴포넌트가 다시 렌더링되더라도, `count`가 바뀌지 않았다면 `doubledCount`는 다시 계산되지 않고 이전 값을 재사용한다.
+
+## 객체와 배열에서 useMemo가 필요한 경우
+
+JavaScript에서 객체와 배열은 값이 같아 보여도 새로 생성되면 다른 참조값을 가진다.
+
+```tsx
+const user = {
+ name: 'Kim',
+ age: 20,
+};
+```
+
+위 코드는 컴포넌트가 렌더링될 때마다 새로운 객체를 만든다.
+
+객체의 내용이 같더라도 메모리 주소가 다르기 때문에 React는 다른 값으로 판단할 수 있다.
+
+```tsx
+import { useMemo } from 'react';
+
+function Parent() {
+ const user = useMemo(() => {
+ return {
+ name: 'Kim',
+ age: 20,
+ };
+ }, []);
+
+ return ;
+}
+```
+
+위 코드처럼 `useMemo`를 사용하면 `user` 객체는 처음 렌더링될 때만 생성된다.
+
+이후 다시 렌더링되어도 같은 객체 참조값을 유지한다.
+
+---
+
+## useMemo와 React.memo의 차이
+
+[React.memo에 대해](https://github.com/DeepDive-FE/DeepDive-React/blob/%EB%AF%BC%ED%98%81/week-03/week-02/%EA%B9%80%EB%AF%BC%ED%98%81.md#reactmemo)
+
+`useMemo`와 `React.memo`는 모두 불필요한 작업을 줄이기 위해 사용한다.
+
+하지만 메모이제이션하는 대상이 다르다.
+
+| 구분 | useMemo | React.memo |
+| --- | --- | --- |
+| 종류 | Hook | 고차 컴포넌트 |
+| 메모이제이션 대상 | 계산된 값 | 컴포넌트 |
+| 사용 위치 | 컴포넌트 내부 | 컴포넌트 선언부 |
+| 목적 | 불필요한 계산 방지 | 불필요한 컴포넌트 렌더링 방지 |
+| 비교 기준 | 의존성 배열 | props |
+| 대표 사용 예시 | 필터링, 정렬, 합계 계산 결과 저장 | props가 같을 때 자식 컴포넌트 렌더링 방지 |
+
+---
+
+### useMemo로도 컴포넌트를 메모이제이션할 수 있지 않나?
+
+
+```tsx
+const memoizedChild = useMemo(() => {
+ return ;
+}, [name]);
+```
+
+이 방식은 가능하지만, 컴포넌트를 최적화한다는 의도가 `React.memo`보다 덜 직관적일 수 있다.
+
+정확히 말하면 컴포넌트 자체를 메모이제이션한다기보다는, **컴포넌트가 반환된 JSX 결과값을 메모이제이션하는 것**에 가깝다.
+
+반면 `React.memo`는 **컴포넌트 자체를 메모이제이션**한다.
+
+---
+
+# useCallback
+
+`useCallback`은 **함수를 메모이제이션**하기 위해 사용하는 React Hook이다.
+
+즉, 컴포넌트가 다시 렌더링되더라도 특정 함수를 매번 새로 만들지 않고, 이전에 만들어둔 함수를 재사용할 수 있게 해준다.
+
+`useMemo`가 **계산된 값**을 기억한다면, `useCallback`은 **함수 자체**를 기억한다.
+
+```tsx
+const handleClick = useCallback(() => {
+ console.log('버튼 클릭');
+}, []);
+```
+
+`useCallback`은 두 개의 인수를 받는다.
+
+1. 첫 번째 인수: 기억할 콜백 함수
+2. 두 번째 인수: 의존성 배열
+
+```tsx
+const handleClick = useCallback(() => {
+ // 첫 번째 인수: 기억할 콜백 함수
+ console.log('버튼 클릭');
+}, []); // 두 번째 인수: 의존성 배열
+```
+
+의존성 배열의 값이 변경되지 않으면 이전에 생성한 함수를 그대로 재사용한다.
+
+---
+
+## useCallback을 사용하는 이유
+
+부모 컴포넌트가 리렌더링되면 부모 내부에 선언된 함수도 새로 생성된다.
+
+이 함수가 자식 컴포넌트의 props로 전달되면, 자식 컴포넌트는 props가 변경되었다고 판단할 수 있다.
+
+이때 `useCallback`을 사용하면 함수의 참조값을 유지할 수 있다.
+
+---
+
+# useRef
+
+`useRef`는 특정 DOM 요소에 직접 접근하거나, 컴포넌트가 다시 렌더링되더라도 변하지 않는 값을 기억하고 싶을 때 사용하는 React Hook이다.
+
+`useState`와 비슷하게 값을 저장할 수 있지만, `useRef`는 값이 변경되어도 컴포넌트가 리렌더링되지 않는다.
+
+```tsx
+const countRef = useRef(0);
+
+countRef.current += 1;
+```
+
+`useRef`는 객체를 반환하고, 실제 값은 `.current`에 저장된다.
+
+```tsx
+const ref = useRef(initialValue);
+```
+
+- `ref.current`: 저장된 값
+- `initialValue`: 처음 저장할 값
+
+---
+
+## useRef를 사용하는 이유
+
+컴포넌트가 리렌더링되어도 유지되어야 하지만, 값이 바뀐다고 화면을 다시 그릴 필요는 없는 경우에 사용한다.
+
+대표적으로 다음과 같은 경우에 사용한다.
+
+- DOM 요소에 직접 접근할 때
+- `setTimeout`, `setInterval`, `requestAnimationFrame`의 ID를 저장할 때
+- 이전 값이나 최신 상태 값을 저장할 때
+- 값은 유지해야 하지만 리렌더링은 발생시키고 싶지 않을 때
+
+---
+
+## 기본 예시
+
+```tsx
+import { useRef } from 'react';
+
+function Example() {
+ const inputRef = useRef(null);
+
+ const focusInput = () => {
+ inputRef.current?.focus();
+ };
+
+ return (
+
+
+
+
+ );
+}
+```
+
+위 코드에서 `inputRef`는 `input` DOM 요소를 참조한다.
+
+버튼을 클릭하면 `inputRef.current`를 통해 실제 input 요소에 접근하고, `focus()`를 실행할 수 있다.
+
+---
+
+## useState와 useRef의 차이
+
+`useState`와 `useRef`는 모두 값을 저장할 수 있다.
+
+하지만 값이 변경되었을 때 동작 방식이 다르다.
+
+| 구분 | useState | useRef |
+| --- | --- | --- |
+| 값 저장 | 가능 | 가능 |
+| 값 변경 시 리렌더링 | 발생함 | 발생하지 않음 |
+| 값 접근 방식 | state 변수 | `ref.current` |
+| 주 사용 목적 | 화면에 반영되는 상태 관리 | 렌더링과 무관한 값 저장 |
+
+```tsx
+const [count, setCount] = useState(0);
+const countRef = useRef(0);
+```
+
+`count`는 값이 바뀌면 화면을 다시 렌더링한다.
+
+반면 `countRef.current`는 값이 바뀌어도 화면을 다시 렌더링하지 않는다.
+
+---
+
+# useContext
+
+`useContext`는 `React`에서 컴포넌트 간에 데이터를 전역적으로 공유할 수 있게 해주는 Hook이다.
+
+## Context란?
+
+`Context`는 컴포넌트 트리 전체에 값을 공유할 수 있게 해주는 `React`의 기능이다.
+
+일반적으로 `React`에서는 부모 컴포넌트가 자식 컴포넌트에게 데이터를 전달할 때 `props`를 사용한다.
+
+하지만 여러 단계 아래에 있는 컴포넌트까지 같은 값을 전달해야 한다면, 중간 컴포넌트들이 직접 사용하지 않는 `props`를 계속 넘겨줘야 한다.
+
+```tsx
+
+
+
+
+
+
+
+```
+
+이처럼 props를 여러 단계로 전달해야 하는 문제를 **props 내려주기(props drilling)**이라고 한다.
+
+`Context`를 사용하면 `props`를 여러 단계 전달하지 않아도, 필요한 컴포넌트에서 값을 바로 사용할 수 있다.
+
+```tsx
+const value = useContext(MyContext);
+```
+
+`useContext`는 `Context` 객체를 인수로 받고, 해당 `Context`에서 제공하는 값을 반환한다.
+
+```tsx
+const user = useContext(UserContext);
+```
+
+- `UserContext`: 공유할 값을 담고 있는 Context
+- `user`: Context에서 꺼내온 값
+
+---
+
+## 기본 예시
+
+```tsx
+import { createContext, useContext } from 'react';
+
+const UserContext = createContext<{ name: string } | null>(null);
+
+function App() {
+ const user = { name: 'Kim' };
+
+ return (
+
+
+
+ );
+}
+
+function Profile() {
+ const user = useContext(UserContext);
+
+ return
이름: {user?.name}
;
+}
+```
+
+위 코드에서 `UserContext.Provider`는 하위 컴포넌트들에게 `user` 값을 제공한다.
+
+`Profile` 컴포넌트는 props로 `user`를 받지 않아도 `useContext(UserContext)`를 통해 값을 가져올 수 있다.
+
+---
+
+## Provider란?
+
+`Provider`는 `Context` 값을 하위 컴포넌트에게 전달하는 역할을 한다.
+
+```tsx
+
+
+
+```
+
+`Provider`의 `value`에 넣은 값은 그 안에 포함된 모든 하위 컴포넌트에서 사용할 수 있다.
+
+```tsx
+const user = useContext(UserContext);
+```
+
+이렇게 `useContext`를 사용하면 가장 가까운 상위 `Provider`의 값을 가져온다.
+
+---
+
+## useContext 사용 시 주의할 점
+
+`useContext`를 사용하면 `props` 전달을 줄일 수 있지만, 모든 상태를 `Context`로 관리하는 것은 좋지 않다.
+
+---
+
+# useCallback
+
+`useCallback`은 **함수를 메모이제이션**하기 위해 사용하는 React Hook이다.
+
+즉, 컴포넌트가 다시 렌더링되더라도 특정 함수를 매번 새로 만들지 않고, 이전에 만들어둔 함수를 재사용할 수 있게 해준다.
+
+`useMemo`가 **계산된 값**을 기억한다면, `useCallback`은 **함수 자체**를 기억한다.
+
+```tsx
+const handleClick = useCallback(() => {
+ console.log('버튼 클릭');
+}, []);
+```
+
+`useCallback`은 두 개의 인수를 받는다.
+
+1. 첫 번째 인수: 기억할 콜백 함수
+2. 두 번째 인수: 의존성 배열
+
+```tsx
+const handleClick = useCallback(() => {
+ // 첫 번째 인수: 기억할 콜백 함수
+ console.log('버튼 클릭');
+}, []); // 두 번째 인수: 의존성 배열
+```
+
+의존성 배열의 값이 변경되지 않으면 이전에 생성한 함수를 그대로 재사용한다.
+
+---
+
+## useCallback을 사용하는 이유
+
+부모 컴포넌트가 리렌더링되면 부모 내부에 선언된 함수도 새로 생성된다.
+
+이 함수가 자식 컴포넌트의 props로 전달되면, 자식 컴포넌트는 props가 변경되었다고 판단할 수 있다.
+
+이때 `useCallback`을 사용하면 함수의 참조값을 유지할 수 있다.
+
+다만 `useCallback`만으로 자식 컴포넌트의 리렌더링을 막는 것은 아니다.
+자식 컴포넌트의 불필요한 리렌더링을 막고 싶다면 보통 `React.memo`와 함께 사용한다.
+좋아 useReduecer도 써줘
+몇 초 동안 생각함
+
+아래 그대로 .md 파일에 복사해서 사용하면 된다.
+
+# useReducer
+
+`useReducer`는 여러 상태를 하나의 규칙에 따라 관리할 때 사용하는 Hook이다.
+
+`useState`처럼 상태를 관리할 수 있지만, 상태 변경 로직을 컴포넌트 밖으로 분리할 수 있다는 특징이 있다.
+
+상태가 단순할 때는 `useState`를 사용해도 충분하지만, 상태 변경 방식이 복잡하거나 여러 조건에 따라 상태가 바뀐다면 `useReducer`를 사용할 수 있다.
+
+---
+
+## useReducer 기본 형태
+
+```tsx
+const [state, dispatch] = useReducer(reducer, initialState, init);
+```
+
+`useReducer`는 `useState`와 동일하게 길이가 2인 배열이다.
+
+1. `state`: 현재 상태
+2. `dispatch`: 상태 변경을 요청하는 함수
+
+그리고 `useReducer`는 보통 2 ~ 3개의 인수를 받는다.
+
+1. `reducer`: 상태 변경 로직을 담은 `reducer` 함수
+2. `initialState`: 초기 상태값
+3. `init` (필수값 X): 초기값을 지연해서 생성시킬 때 사용하는 함수. useState와 동일하게 게으른 초기화가 일어나며, `initialState`를 인수로 `init` 함수가 실행된다.
+
+---
+
+### reducer 함수란?
+
+`reducer` 함수는 현재 상태와 action을 받아서 새로운 상태를 반환하는 함수다.
+
+```tsx
+function reducer(state, action) {
+ switch (action.type) {
+ case 'INCREASE':
+ return state + 1;
+
+ case 'DECREASE':
+ return state - 1;
+
+ default:
+ return state;
+ }
+}
+```
+
+여기서 `action`은 상태를 어떻게 변경할지 설명하는 객체다.
+
+```tsx
+{ type: 'INCREASE' }
+```
+
+즉, `dispatch`로 action을 보내면 `reducer`가 그 `action`을 보고 상태를 변경한다.
+
+---
+
+## useReducer 예시
+
+```tsx
+import { useReducer } from 'react';
+
+function reducer(state: number, action: { type: 'INCREASE' | 'DECREASE' }) {
+ switch (action.type) {
+ case 'INCREASE':
+ return state + 1;
+
+ case 'DECREASE':
+ return state - 1;
+
+ default:
+ return state;
+ }
+}
+
+function Counter() {
+ const [count, dispatch] = useReducer(reducer, 0);
+
+ return (
+
+
현재 값: {count}
+
+
+
+
+
+ );
+}
+```
+
+위 코드에서 `count`는 현재 상태이고, `dispatch`는 상태 변경을 요청하는 함수다.
+
+```tsx
+dispatch({ type: 'INCREASE' });
+```
+
+위 코드를 실행하면 `reducer` 함수에 현재 상태와 `action`이 전달된다.
+
+```tsx
+reducer(count, { type: 'INCREASE' });
+```
+
+그리고 `reducer`는 `action`의 `type`을 확인한 뒤 새로운 상태를 반환한다.
+
+---
+
+## useReducer의 동작 흐름
+
+```tsx
+
+```
+
+위 버튼을 클릭하면 다음 순서로 동작한다.
+
+1. `dispatch` 함수가 실행된다.
+2. `{ type: 'INCREASE' }` `action`이 `reducer` 함수로 전달된다.
+3. `reducer` 함수가 현재 상태와 `action`을 비교한다.
+4. `action type`에 맞는 새로운 상태를 반환한다.
+5. `React`가 반환된 상태로 컴포넌트를 다시 렌더링한다.
+
+---
+
+## 객체 상태를 관리하는 예시
+
+`useReducer`는 여러 상태값을 하나의 객체로 관리할 때도 자주 사용한다.
+
+```tsx
+import { useReducer } from 'react';
+
+type State = {
+ count: number;
+ text: string;
+};
+
+type Action =
+ | { type: 'INCREASE' }
+ | { type: 'DECREASE' }
+ | { type: 'CHANGE_TEXT'; text: string };
+
+const initialState: State = {
+ count: 0,
+ text: '',
+};
+
+function reducer(state: State, action: Action): State {
+ switch (action.type) {
+ case 'INCREASE':
+ return {
+ ...state,
+ count: state.count + 1,
+ };
+
+ case 'DECREASE':
+ return {
+ ...state,
+ count: state.count - 1,
+ };
+
+ case 'CHANGE_TEXT':
+ return {
+ ...state,
+ text: action.text,
+ };
+
+ default:
+ return state;
+ }
+}
+
+function Example() {
+ const [state, dispatch] = useReducer(reducer, initialState);
+
+ return (
+
+ );
+}
+```
+
+위 코드에서는 `count`와 `text`를 하나의 `state` 객체로 관리한다.
+
+상태를 변경할 때는 직접 값을 수정하지 않고, `dispatch`를 통해 action을 전달한다.
+
+```tsx
+dispatch({ type: 'CHANGE_TEXT', text: e.target.value });
+```
+
+그러면 `reducer` 함수에서 `action type`에 맞게 새로운 상태를 반환한다.
+
+---
+
+## useState와 useReducer의 차이
+
+`useState`와 `useReducer`는 모두 상태를 관리하기 위한 Hook이다.
+
+다만 상태 변경 로직의 위치와 관리 방식에 차이가 있다.
+
+| 구분 | useState | useReducer |
+| --- | --- | --- |
+| 사용 목적 | 단순한 상태 관리 | 복잡한 상태 관리 |
+| 상태 변경 방식 | setter 함수로 직접 변경 | dispatch로 action 전달 |
+| 상태 변경 로직 | 컴포넌트 내부에 작성되는 경우가 많음 | reducer 함수에 분리 |
+| 적합한 상황 | boolean, string, number 같은 단순 상태 | 여러 조건에 따라 바뀌는 객체 상태 |
+| 예시 | `setCount(count + 1)` | `dispatch({ type: 'INCREASE' })` |
+
+---
+
+## useReducer를 사용하는 상황
+
+다음과 같은 경우에는 `useReducer`를 고려할 수 있다.
+
+- 상태값이 여러 개이고 서로 관련이 있는 경우
+- 상태 변경 로직이 복잡한 경우
+- 하나의 상태가 여러 `action`에 의해 변경되는 경우
+- 상태 변경 과정을 명확하게 관리하고 싶은 경우
+- 컴포넌트 내부에서 상태 변경 코드가 너무 길어지는 경우
+
+---
+
+# useLayoutEffect
+
+## 페인트(Paint)란?
+
+브라우저는 React 컴포넌트가 렌더링한 결과를 바로 화면에 보여주는 것이 아니라, 여러 단계를 거쳐 화면을 그린다.
+
+간단히 보면 다음과 같은 흐름이다.
+
+1. React가 컴포넌트를 렌더링한다.
+2. 변경된 내용을 DOM에 반영한다.
+3. 브라우저가 화면에 그릴 위치와 크기를 계산한다.
+4. 브라우저가 실제 화면에 픽셀을 그린다.
+
+여기서 브라우저가 실제 화면에 내용을 그리는 과정을 **페인트(Paint)**라고 한다.
+
+> 💡 페인트란, 브라우저가 DOM과 스타일 계산 결과를 바탕으로 실제 화면에 UI를 그리는 과정이다.
+
+즉, 사용자가 화면에서 보는 결과가 만들어지는 단계라고 볼 수 있다.
+
+---
+
+## useLayoutEffect란?
+
+`useLayoutEffect`는 React 컴포넌트가 렌더링되고 DOM에 반영된 직후, 브라우저가 화면을 페인트하기 전에 실행되는 Hook이다.
+
+```tsx
+useLayoutEffect(() => {
+ console.log('브라우저가 화면을 그리기 전에 실행된다.');
+}, []);
+```
+
+`useLayoutEffect`는 형태상 `useEffect`와 거의 동일하다.
+
+```tsx
+useLayoutEffect(() => {
+ // 첫 번째 인수: 실행할 콜백 함수
+}, []); // 두 번째 인수: 의존성 배열
+```
+
+---
+
+## useEffect와 useLayoutEffect의 실행 시점 차이
+
+`useEffect`와 `useLayoutEffect`의 가장 큰 차이는 실행 시점이다.
+
+| 구분 | 실행 시점 |
+| --- | --- |
+| `useEffect` | 브라우저가 화면을 페인트한 후 실행 |
+| `useLayoutEffect` | 브라우저가 화면을 페인트하기 전에 실행 |
+
+즉, `useEffect`는 화면이 먼저 그려진 후 실행되고, `useLayoutEffect`는 화면이 그려지기 전에 실행된다.
+
+---
+
+### useLayoutEffect 실행 흐름
+
+```tsx
+useLayoutEffect(() => {
+ console.log('useLayoutEffect 실행');
+}, []);
+```
+
+`useLayoutEffect`는 다음과 같은 흐름으로 실행된다.
+
+1. 컴포넌트가 렌더링된다.
+2. 변경된 내용이 DOM에 반영된다.
+3. `useLayoutEffect`가 실행된다.
+4. 브라우저가 화면을 페인트한다.
+5. `useEffect`가 실행된다.
+
+즉, 사용자가 화면을 보기 전에 `useLayoutEffect` 안의 작업이 먼저 실행된다.
+
+---
+
+## useLayoutEffect를 사용하는 이유
+
+`useLayoutEffect`는 화면이 그려지기 전에 DOM을 읽거나 수정해야 할 때 사용한다.
+
+대표적으로 다음과 같은 경우에 사용할 수 있다.
+
+- DOM 요소의 크기나 위치를 측정해야 하는 경우
+- 측정한 값을 바탕으로 바로 스타일을 변경해야 하는 경우
+- 화면이 깜빡이는 현상을 막아야 하는 경우
+- 스크롤 위치를 조정해야 하는 경우
+
+예를 들어 어떤 요소의 높이를 측정한 뒤, 그 높이에 따라 위치를 조정해야 한다고 가정해보자.
+
+이 작업을 `useEffect`에서 처리하면 브라우저가 먼저 화면을 그린 뒤 위치를 수정하기 때문에, 사용자가 순간적으로 잘못된 위치의 화면을 볼 수 있다.
+
+반면 `useLayoutEffect`는 화면이 그려지기 전에 실행되므로, 위치를 수정한 결과가 바로 화면에 나타난다.