diff --git "a/week-03/\352\271\200\354\244\200\354\227\264.md" "b/week-03/\352\271\200\354\244\200\354\227\264.md"
new file mode 100644
index 0000000..907b8f6
--- /dev/null
+++ "b/week-03/\352\271\200\354\244\200\354\227\264.md"
@@ -0,0 +1,575 @@
+
리액트 훅 깊게 살펴보기
+
useState
+
+- useState는 함수 컴포넌트 내부에서 상태를 정의하고, 관리하는 훅이다.
+
+- 매번 실행되는 함수 컴포넌트 환경에서 state 값을 유지하고 사용하기 위해서 리액트는 클로저를 활용하고 있다.
+
+
+```tsx
+// useState 기본 사용법
+import { useStaet } from "react"
+
+const [state, setState] = useState("초깃값"); // 초깃값이 없다면 undefined 할당
+```
+
+
게으른 초기화
+
+- useState에 변수 대신 함수를 넘기는 것
+
+- 리액트 컴포넌트가 렌더링될 때마다 상태 초기화 코드를 실행하는 대신, 초기화 함수는 첫 번째 렌더링 시에만 호출된다.
+
+- 무거운 연산이 요구될 때 (localStorage, sessionStorage에 대한 접근 + map, filter, find 등 배열에 대한 접근, 초깃값 계산)
+
+
+
+
useEffect
+
+- 콜백, 의존성 배열을 인수로 받는다.
+
+- 클래스 컴포넌트의 생명주기 메서드와 비슷한 작동을 구현할 수 있다.
+
+- 의존성 배열에 빈 배열을 두면 컴포넌트가 마운트될 때만 실행된다.
+
+- 클린업 함수는 컴포넌트가 언마운트될 때 실행된다.
+
+---
+
+
useEffect는 어떻게 의존성 배열이 변경된 것을 알고 실행될까?
+
+- 컴포넌트가 처음 렌더링될 때, useEffect는 실행되고 의존성 배열(dependency array) 내의 값을 기록해둔다.
+
+- 이후 컴포넌트가 다시 렌더링되면 리액트는 새로운 렌더링에서 의존성 배열의 값과 이전 렌더링 시 기록해둔 값을 비교한다.
+
+- 리액트는 얕은 비교(참조 비교)를 사용하여 의존성 배열의 각 요소를 비교한다.
+
+- 의존성 배열의 값 중 하나라도 이전 값과 다른 경우, 리액트는 해당 useEffect를 다시 실행한다.
+
+- 부수 효과가 실행될 때마다 정리(clean-up) 함수가 실행된다(정리 함수가 반환된 경우).
+
+- 렌더링할 때마다 의존성에 있는 값을 보면서 이 의존성의 값이 이전과 다른 게 하나라도 있으면 부수효과를 실행하는 평범한 함수다.
+
+```tsx
+import React, { useState, useEffect } from 'react';
+
+function ExampleComponent() {
+ const [count, setCount] = useState(0);
+ const [text, setText] = useState('');
+
+ useEffect(() => {
+ console.log('부수 효과 실행: count 또는 text가 변경됨');
+
+ return () => {
+ console.log('정리 작업');
+ };
+ }, [count, text]); // count 또는 text가 변경될 때마다 실행됨
+
+ return (
+
+
+ 1. eslint-disable-line react-hooks/exhaustive-eps 주석 자제
+ - useEffect 인수 내부에서 사용하는 값 중 의존성 배열에 있지 않는 경우 경고를 발생시켜주는데 의도치 못한 버그발생의 원인이 될 수 있다.
+
+
+
+ 2. useEffect의 첫번째 인수에 함수명 부여
+ - useEffect를 사용하는 많은 코드에서 useEffect의 첫 인수로 익명 함수를 부여한다. 하지만 useEffect의 수가 많아지거나 로직이 복잡해지면 적절한 이름을 붙여주자.
+
+```tsx
+useEffect(function fetchData() { // 비동기 작업 처리 }, [dependency]);
+```
+
+ 3. 거대한 useEffect를 만들지 말자
+ - useEffect의 부수효과가 커질수록 성능에 악영향을 미친다. 큰 useEffect를 만들더라도 작은 useEffect들로 분리하는것이 좋다.
+
+
+
+ 4. 불필요한 외부 함수를 만들지 말자
+ - useEffect가 실행하는 콜백 또한 불필요하게 존재하면 안된다.
+
+```tsx
+// 나쁜 예: 불필요한 외부 함수 생성
+const fetchData = () => { // 비동기 작업 처리 };
+useEffect(() => { fetchData(); }, [dependency]);
+
+// 좋은 예: 필요할 때만 함수 정의
+useEffect(() => {
+ const fetchData = () => { // 비동기 작업 처리 }; fetchData(); }, [dependency]);
+```
+
+
+
+---
+
+
useEffect 콜백으로 비동기함수를 못넣는 이유
+
+```tsx
+useEffect(() => {
+ async function fetchData() {
+ const result = await fetch('');
+ setData(result.data);
+ }
+
+ fetchData(); // 비동기 함수를 직접 호출
+
+ // 다음 코드는 fetchData가 완료되기를 기다리지 않고 실행될 수 있음
+ console.log('Fetch 데이터 설정 후 실행');
+
+ // 콜백 내에서의 비동기 함수 호출은 정리 함수가 실행되기 전에 완료될 수 있음
+ return () => {
+ console.log('정리 함수');
+ };
+}, []);
+```
+```tsx
+useEffect(() => {
+ async function fetchData() {
+ const result = await fetch('');
+ return result.data;
+ }
+
+ fetchData().then(data => {
+ setData(data); // 데이터 설정
+ });
+
+ return () => {
+ console.log('정리 함수');
+ };
+}, []);
+```
+
+
+
+
useMemo
+
+- 비용이 큰 연산에 대한 결과를 저장(메모이제이션)해 두고, 이 저장된 값을 반환하는 훅
+생성함수, 배열을 인수로 받는다.
+
+- 렌더링 발생 시 의존성 배열의 값이 변경되지 않았으면 함수를 재실행하지 않고 이전에 기억해 둔
+
+- 해당 값을 반환하고, 의존성 배열의 값이 변경됐다면 첫 번째 인수의 함수를 실행한 후에 그 값을 반환하고 그 값을 다시 기억해 둔다.
+
+
+
+
useCallback
+
+- 인수로 넘겨받은 콜백 자체를 기억한다.
+
+- 특정 함수를 새로 만들지 않고 다시 재사용한다.
+
+
+- MyComponent에서 ChildComponent에게 전달하는 name, value, onChange Props는 모두 부모 컴포넌트의 상태에 의존적입니다. 따라서 status1 또는 status2 상태가 변경될 때마다 해당 ChildComponent의 모든 Props가 변경된다.
+
+
메모이제이션된 Props
+- memo로 ChildComponent를 메모이제이션하더라도, 함수나 객체 같은 참조 타입의 Props가 변경될 때마다 새로운 Props 객체가 생성되므로, React.memo의 최적화 효과를 제대로 볼 수 없다.
+
+
+
+```tsx
+const toggle1 = useCallback(() => {
+ setStatus1((prevStatus) => !prevStatus);
+}, []);
+
+const toggle2 = useCallback(() => {
+ setStatus2((prevStatus) => !prevStatus);
+}, []);
+```
+
+- Props가 변경되는 경우, 새로운 Props 객체가 생성되어 메모이제이션된 ChildComponent에 새로 전달될 수 있다. useCallback으로 toggle1 함수가 setStatus1을 호출할 때마다 새로운 함수가 생성되는 것을 막아 성능을 최적화한다.
+
+
+
+
useMemo vs. useCallback
+
+| 구분 | useMemo | useCallback |
+|---|---|---|
+| 목적 | 값 메모이징 | 함수 메모이징 |
+| 사용 시기 | 성능 향상이 필요한 복잡한 연산 | 함수를 props로 전달할 때 |
+| 예시 | 큰 데이터 세트에서 필터링/정렬 | 자식 컴포넌트에 콜백 함수 전달 |
+
+```tsx
+import { useState, useMemo, useCallback } from 'react';
+
+function MyComponent() {
+ const [numbers, setNumbers] = useState([1, 2, 3, 4, 5]);
+ const [count, setCount] = useState(0);
+
+ // numbers 배열의 합계를 계산하고 메모이징한다.
+ // numbers 배열이 변경되지 않는 한 재계산되지 않는다.
+ const total = useMemo(() => {
+ console.log('총 계산 중...');
+ return numbers.reduce((acc, num) => acc + num, 0);
+ }, [numbers]);
+
+ // handleClick 함수를 메모이징한다.
+ // count 값이 변경되지 않는 한 새로운 함수가 생성되지 않는다.
+ const handleClick = useCallback(() => {
+ setCount(count + 1);
+ }, [count]);
+
+ return (
+
+
총 합계: {total}
+
+
카운트: {count}
+
+ );
+}
+```
+
+
useRef
+
+- 컴포넌트 내부에서 렌더링이 일어나도 변경 가능한 상태값을 저장한다.
+
+- 반환값인 객체 내부에 있는 current로 값에 접근, 변경할 수 있다.
+
+- 값이 변하더라도 렌더링을 발생시키지 않는다.
+
+
useRef을 사용하는 이유
+
+1. DOM 접근 및 조작
+
+```tsx
+ const inputRef = useRef(null);
+ // useRef를 사용해 input 요소에 대한 참조 생성
+
+ const focusInput = () => {
+ inputRef.current.focus(); // 버튼 클릭 시 input 요소에 포커스를 줌
+ };
+
+ return (
+ <>
+
+
+ >
+ );
+```
+
+
+
+2. 값의 변경 감지 및 보존
+ - useRef는 값이 변경되더라도 컴포넌트가 다시 렌더링되지 않고 값을 유지할 수 있다.
+
+```tsx
+const previousValueRef = useRef(value);
+// useRef를 사용해 이전 값 저장
+
+ useEffect(() => {
+ if (previousValueRef.current !== value) {
+ // 이전 값과 현재 값 비교
+ console.log('값이 변경되었습니다:', previousValueRef.current, '에서', value, '로'); // 값이 변경될 때 콘솔에 출력
+ previousValueRef.current = value; // 이전 값 업데이트
+ }
+ }, [value]); // value가 변경될 때 useEffect가 실행되도록 설정
+
+ return
현재 값: {value}
;
+```
+
+
useContext
+
+- 부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달할 때 사용하는 훅
+
+
Props Drilling
+
+- 여러 컴포넌트를 거쳐 데이터를 전달하는 것 중간에 위치한 컴포넌트에서는 필요없는 props를 전달해야할 수 있어 가독성이 떨어질 수 있다. → Context 등장
+
+```tsx
+
+
+
+
+
+
+
+
+```
+
+
Context
+
+- props 전달 없이도 선언한 하위 컴포넌트 모두에서 자유롭게 원하는 값을 사용할 수 있다.
+
+```tsx
+// ThemeContext.js
+// createContext로 ThemeContext를 생성하고 기본값으로 'light'를 설정
+import { createContext } from 'react';
+
+const ThemeContext = createContext('light');
+
+export default ThemeContext;
+```
+```tsx
+// App.js
+import React, { useState } from 'react';
+import ThemeContext from './ThemeContext';
+import ChildComponent from './ChildComponent';
+
+const App = () => {
+ const [theme, setTheme] = useState('light');
+
+ return (
+ // ThemeContext.Provider를 사용하여 하위 컴포넌트에 theme 값을 제공
+
+
+
+- useContext를 활용한 컴포넌트는 재활용이 어려워 진다.
+
+- 컨텍스트와 useContext는 상태관리를 위한 API가 절대 아니다. 컨텍스트는 상태를 주입해주는 API다.
+
+- 어떤 상태를 기반으로 다른 상태를 만들어 낼 수 있어야 한다.
+필요에 따라 이런 상태변화를 최적화 할 수 있어야 한다.
+→ 상태관리 라이브러리를 위한 두가지 조건을 useContext는 충족시켜주지 못하고 단순히 props 값을 하위로 전달해 줄 뿐이다.
+
+
+
+
useReducer
+
+- useState의 심화 버전 (상태 관리를 위해 사용되는 훅)
+
+- 상태 관리가 복잡하고 여러 액션에 따라 상태를 업데이트해야 할 때 유용하다.
+
+- 반환값
+ - state: 현재 useState가 가진 값
+ - dispatcher: state를 업데이트 하는 함수
+
+- 3개의 인수
+ - reducer : useReducer의 기본 action을 정의하는 함수
+ - initialState : useReducer의 초기값
+ - init : 초기값을 지연해서 생성하고 싶을 때 사용하는 함수
+
+```tsx
+import React, { useReducer } from 'react';
+
+// 초기 상태 정의
+const initialState = { count: 0 };
+
+// 리듀서 함수 정의
+const reducer = (state, action) => {
+ switch (action.type) {
+ case 'increment':
+ return { count: state.count + 1 };
+ case 'decrement':
+ return { count: state.count - 1 };
+ case 'reset':
+ return initialState;
+ default:
+ throw new Error();
+ }
+};
+
+const Counter = () => {
+ // useReducer로 상태와 리듀서를 연결
+ const [state, dispatch] = useReducer(reducer, initialState);
+
+ return (
+
+
Count: {state.count}
+
+
+
+
+ );
+};
+
+export default Counter;
+```
+
+
+
+
useImperativeHandle
+
+- 부모에게서 넘겨받은 ref를 원하는 대로 수정할 수 있는 훅
+
+
forwardRef
+
+- 리액트 컴포넌트에서 ref를 직접 전달할 수 있게 해주는 메커니즘
+
+- 리액트에서 일반적으로 자식 컴포넌트에 직접적으로 ref를 전달할 수 없다.
+
+- forwardRef를 사용하면 부모 컴포넌트에서 자식 컴포넌트에 ref를 직접 전달할 수 있다. (DOM 요소에 직접 접근해야 할 때 유용)
+
+```tsx
+import React, { forwardRef, useRef, useImperativeHandle } from 'react';
+
+// forwardRef로 외부에서 ref를 직접 전달받을 수 있는 컴포넌트 생성
+const FancyInput = forwardRef((props, ref) => {
+ // useRef로 내부에서 관리할 변수 생성
+ const inputRef = useRef();
+
+ // useImperativeHandle을 사용하여 외부로 노출할 메서드 정의
+ useImperativeHandle(ref, () => ({
+ focus: () => {
+ inputRef.current.focus(); // 내부 input 요소에 포커스
+ }
+ }));
+
+ return ;
+});
+
+// App 컴포넌트에서 FancyInput을 사용합니다.
+const App = () => {
+ const inputRef = useRef();
+
+ const handleClick = () => {
+ // FancyInput 컴포넌트의 focus 메서드를 호출해 포커스
+ inputRef.current.focus();
+
+ return (
+
+
+
+
+ );
+};
+
+export default App;
+```
+
+
+
+
useLayoutEffect
+
+- useEffect와 동일하나 모든 DOM의 변경 후에 동기적으로 발생한다.
+
+- 모든 DOM의 변경 후에 useLayoutEffect의 콜백 함수 실행이 동기적으로 발생한다.
+
+- DOM은 계산됐지만 화면에 반영되기 전에 하고싶은 작업이 있을 때 씀.
+
+ex) 사용자가 특정 버튼을 클릭하면 페이지의 특정 위치로 스크롤을 이동하고 싶은 경우, 특정 요소의 크기나 위치를 계산하여 다른 요소의 스타일을 업데이트해야 하는 경우, DOM 변경에 따른 애니메이션을 동기적으로 실행해야 하는 경우
+
+1. 리액트가 DOM 업데이트
+2. **useLayoutEffect 실행**
+3. 브라우저에 변경 사항 반영
+4. useEffect 실행
+
+
+
+
useDebugValue
+
+- 컴포넌트의 디버깅을 돕기 위해 사용
+
+- 사용자 정의 훅 내부의 내용에 대한 정보를 남길 수 있는 훅
+
+- 두 번째 인수로 포매팅 함수를 전달하면 이에 대한 값이 변경됐을 때만 호출되어 포매팅된 값을 노출한다.
+
+```tsx
+import { useDebugValue } from 'react';
+
+function useCustomHook(value) {
+ // value 값에 따라 다른 디버그 레이블을 설정
+ useDebugValue(value > 10 ? 'High' : 'Low');
+
+ // 실제 커스텀 훅의 로직
+ // ...
+}
+```
+
+
훅의 규칙
+
+- 최상위에서만 훅을 호출해야 한다.
+
+- 훅을 호출할 수 있는 것은 리액트 함수 컴포넌트, 사용자 정의 훅 두 가지 경우 뿐.
+
+
정리
+
+## 사용자 정의 훅 vs. 고차 컴포넌트
+
+| 구분 | 사용자 정의 훅 | 고차 컴포넌트 |
+|---|---|---|
+| 개념 | 함수 컴포넌트에서 사용할 수 있는 재사용 가능한 로직을 캡슐화한 함수 | 다른 컴포넌트를 입력으로 받아 새로운 컴포넌트를 반환하는 함수 |
+| 구현 방식 | 함수 컴포넌트 내부에서 다른 훅(`useState`, `useEffect` 등)을 호출하여 구현 | 기존 컴포넌트를 입력으로 받아 새로운 컴포넌트를 반환하는 함수로 구현 |
+| 사용 방법 | 함수 컴포넌트 내에서 직접 호출하여 사용 | 기존 컴포넌트를 새로운 컴포넌트로 감싸서 사용 |
+| 컴포넌트 구조 | 함수 컴포넌트 내부에 포함되어 있어 컴포넌트 트리에 영향을 미치지 않음 | 새로운 컴포넌트를 반환하므로 컴포넌트 트리에 영향을 미침 |
+| 디버깅 | 함수 컴포넌트 내부에 있어 디버깅이 상대적으로 쉬움 | 새로운 컴포넌트가 생성되므로 디버깅이 상대적으로 복잡할 수 있음 |
+