---
# System prepended metadata

title: 모던 리액트 딥다이브 3장

---

---
title: '3장 리액트 훅 깊게 살펴보기'
created: 2024-04-16
updated: 2024-04-16
tags:
  - 'Frontend'
  - 'Study'
  - 'Book'
---

# 중요한 부분 정리

## 1. 리액트의 모든 훅 파헤치기

### 1. useState

- `useState`: 함수형 컴포넌트 내부에서 상태를 정의하고 이 상태를 관리할 수 있게 해주는 훅
- `useState`를 사용하지 않고 컴포넌트 내부에서 자체적으로 변수를 사용해도 변수 값은 변경되지 않는다. 리액트의 렌더링은 함수형 컴포넌트에서 반환한 결과물인 return의 값을 비교해 실행되기 때문이다.
- 내부에서 클로저를 이용했다. `useState` 실행 종료 후에도 state를 계속 참조할 수 있다.
- **게으른 초기화**: `useState` 인수로 특정한 값을 넘기는 함수를 인수로 넣어줄 수 있다. 초깃값이 복잡하거나 무거운 연산을 포함하고 있을 때 사용한다. 게으른 초기화 함수는 state가 처음 만들어질 때만 사용된다.

### 2. useEffect

- `useEffect`는 알려진 것처럼 생명주기 메서드를 대체하기 위해 만들어진 훅이 아니다.
- 컴포넌트가 렌더링된 후에 어떠한 부수 효과를 일으키고 싶을 때 사용하는 훅이다.
- 더 정확하게는 애플리케이션 내 컴포넌트의 여러 값들을 활용해 동기적으로 부수 효과를 만드는 매커니즘이다.
- `useEffect`는 클라이언트 사이드에서 실행되는 것을 보장해준다.
- **클린업 함수**: 언마운트라기보다는 함수형 컴포넌트가 리렌더링됐을 때 의존성 변화가 있었을 당시 이전의 값을 기준으로 실행되는, 이전 상태를 청소해주는 개념이다. 특정 이벤트의 핸들러가 무한히 추가되는 것을 방지한다.
- 왜 `useEffect`의 콜백 인수로 비동기 함수를 바로 넣을 수 없을까?
    - `useEffect`에서 비동기로 함수를 호출할 경우 경쟁 상태가 발생할 수 있고 cleanup 함수의 실행 순서도 보장할 수 없기 때문이다.

- 주의할 점
    - `eslint-disable-line react-hooks/exhaustive-deps` 주석은 최대한 자제하라
    - useEffect의 첫 번째 인수에 함수명을 부여하라
    - 거대한 `useEffect`를 만들지 마라. 적은 의존성 배열을 사용하는 여러 개의 `useEffect`로 분리하는 것이 낫다.
    - 불필요한 외부 함수를 만들지 마라

### 3. useMemo

- `useMemo`는 비용이 큰 연산에 대한 결과를 저장(Memoization)해 두고, 이 저장된 값을 반환하는 훅이다.
- 첫 번째 인수로 어떠한 값을 반환하는 생성 함수를, 두 번째 인수로 해당 함수가 의존하는 값의 배열을 받는다.

### 4. useCallback

- useCallback은 인수로 넘겨받은 콜백 자체를 기억한다.
- 첫번째 인수로 함수를, 두번째 인수로 의존성 배열을 받는다.
- useCallback에 기명함수를 넘겨주면 크롬 메모리탭에서 디버깅을 용이하게 할 수 있다.
- 함수를 메모이제이션 하는 용도라면 useMemo보다는 useCallback을 사용하는 것이 가독성이 좋다.

### 5. useRef

- useRef는 반환값인 객체 내부에 있는 current로 값에 접근 또는 변경할 수 있다.
- useRef는 그 값이 변하더라도 렌더링을 발생시키지 않는다.
- useRef의 최초 기본값은 return문에 정의해둔 DOM이 아니고 useRef()로 넘겨받은 인수다.
- useRef가 선언될 당시에는 컴포넌트가 렌더링되기 전이라 undefined 상태이다.

### 6. useContext

- Context를 사용하면 명시적인 props 전달 없이도 선언한 하위 컴포넌트 모두에서 자유롭게 값을 사용할 수 있다.
- 상위에 Context.Provider 선언 후 사용
- 여러개의 Provider가 있다면 가장 가까운 Provider의 값을 가져오게 된다.
- 컴포넌트 트리가 복잡해질 수록 Context 사용이 어려워진다. => 에러를 방지하려면 Context가 초기화되어 값을 내리주는지 확인하는 방어코드를 사용하자.

주의할 점
- useContext를 함수 컴포넌트 내부에서 사용하면 Provider에 의존성이 생기기 때문에, 컴포넌트 재활용이 어려워진다.
- useContext는 상태관리를 위한 API가 아니라 상태를 주입해주는 API다.
- 상태관리 라이브러리가 되기 위한 최소 조건 2가지
    1. 어떠한 상태를 기반으로 다른 상태를 만들어낼 수 있어야 한다
    2. 필요에 따라 이런 상태를 최적화 할 수 있어야 한다.
- useContext는 props drilling 을 피하게 해줄 뿐 사용했을 때 렌더링이 최적화되지는 않는다.

### 7. useReducer

- useState와 비슷한 형태를 띠지만 좀 더 복잡한 상태값을 미리 정의해 놓은 시나리오에 따라 관리할 수 있다.
- state를 사용하는 로직과 이를 관리하는 비즈니스 로직을 분리할 수 있어 state 관리가 쉬워진다.
- useReducer나 useState 둘 다 세부 작동과 쓰임에만 차이가 있을 뿐, 클로저를 활용해 값을 가둬서 state를 관리한다.

### 8. useImperativeHandle

- forwardRef가 탄생한 배경은 ref를 전달하는 데 있어서 일관성을 제공하기 위해서다.
- useImperativeHandle은 부모에게 넘겨받은 ref를 원하는 대로 수정할 수 있는 훅이다.

### 9. useLayoutEffect

- 이 함수의 시그니처는 `useEffect` 와 동일하나, 모든 DOM의 변경 후에 동기적으로 발생한다.
- DOM은 계산됐지만 이것이 화면에 반영되기 전에 하고 싶은 작업이 있을 때만 사용하는 것이 좋다.
    - 특정 요소에 따라 DOM 요소를 기반으로 한 애니메이션, 스크롤 위치 제어 등

### 10. useDebugValue

- `useDebugValue`는 사용자 정의 훅 내부의 내용에 대한 정보를 남길 수 있는 훅이다.
- 첫 번째 인수로 전달한 값이 변경되었을 때 두 번째 인수로 전달한 포매팅 함수를 호출하여 포매팅된 값을 노출한다.
- 일반적으로 프로덕션 웹서비스가 아닌 개발 과정에서 사용한다.
- 오직 다른 훅 내부에서만 실행할 수 있고, 컴포넌트 레벨에서 실행하면 작동하지 않는다.

### 11. 훅의 규칙

#### 규칙1. 컴포넌트 최상단에서만 훅을 호출해야 한다.

- 반복문이나 조건문, 중첩된 함수 내에서 훅을 실행할 수 없다.
- 각 훅이 파이버 객체 내에서 순서에 의존해 값을 저장하고 있기 때문이다.

#### 규칙2. 훅을 호출할 수 있는 것은 리액트 함수 컴포넌트, 사용자 정의 훅 두 가지 뿐이다.

## 2. 사용자 정의 훅과 고차 컴포넌트 중 무엇을 써야 할까?

- 사용자 정의 훅이 필요한 경우
: 해당 컴포넌트가 반환하는 렌더링 결과물에 영향을 미치지 않음. (사이드 이펙트 적음)
    - `useState`, `useEffect`와 같이 리액트에서 제공하는 훅으로만 공통 로직을 분리할 수 있을 때
    - 단순히 컴포넌트 전반에 걸쳐 동일한 로직으로 값을 제공할 때
    - 특정한 훅의 작동을 취할 때
- 고차 컴포넌트를 사용해야하는 경우: 렌더링에 영향을 미치는 로직이 존재함
    - 함수 컴포넌트의 반환값, 즉 렌더링의 결과물에도 영향을 미치는 공통 로직이라면 고차 컴포넌트를 사용하는 것이 좋다.
    - 고차 컴포넌트가 많아질수록 복잡성이 기하급수적으로 증가하므로 신중하게 사용해야 한다.

### 참고자료

- https://github.com/uidotdev/usehooks
- https://github.com/toss/slash
- https://slash.page/ko/
- https://youtu.be/NwLWX2RNVcw?si=X1QPkEw8h3iKmOqb
- https://overreacted.io/a-complete-guide-to-useeffect/
- https://rinae.dev/posts/a-complete-guide-to-useeffect-ko/

# 회고

## Keep (현재 만족하고 있는 부분)

- 공유 시간에 더 많은 것을 공유할 수 있어서 좋았습니다.
- 분량이 적절하게 조절된 것 같아 좋았습니다!
- 지난주와 마찬가지로 분량이 적절해서 좋았습니다!
- 내용 공유 시간을 조금 더 길게 가져가니 관련된 다양한 이야기를 나눌 수 있어 좋았습니다.
- 공유 시간이 길어져서 더 많은 이야기를 나눌 수 있어서 좋았습니다.
- 분량이 딱맞는것 같습니다!집중하게 읽게되어 좋습니다.
- 매주 진행 잘해주셔서 감사합니다 ~

## Problem (개선이 필요한 부분)

- 책읽기 마치고 5분 정도 쉬는시간 넣어도 좋을 것 같습니다.

## Try (해결책)

- 시간 조정
    * 30분 읽기
    * 5분 쉬기
    * 30분 읽기
    * 5분 쉬기
    * 20분 공유하기
    * 15분 정리하기
    * 15분 회고
