|
| 1 | +# 03장: 리액트 훅 깊게 살펴보기 |
| 2 | + |
| 3 | +리액트를 이루는 핵심 요소들을 깊게 살펴보고, 리액트의 렌더링 과정을 이해하는 장입니다. |
| 4 | + |
| 5 | +<br> |
| 6 | + |
| 7 | +- [03장: 리액트 훅 깊게 살펴보기](#03장-리액트-훅-깊게-살펴보기) |
| 8 | + - [3.1 리액트 훅 깊게 살펴보기](#31-리액트-훅-깊게-살펴보기) |
| 9 | + - [3.1.1 useState](#311-usestate) |
| 10 | + - [3.1.2 useEffect](#312-useeffect) |
| 11 | + - [3.1.3 useMemo](#313-usememo) |
| 12 | + - [3.1.4 useCallback](#314-usecallback) |
| 13 | + - [3.1.5 useRef](#315-useref) |
| 14 | + - [3.1.6 useContext](#316-usecontext) |
| 15 | + - [3.1.7 useReducer](#317-usereducer) |
| 16 | + - [3.1.8 useImperativeHandle](#318-useimperativehandle) |
| 17 | + - [3.1.9 useLayoutEffect](#319-uselayouteffect) |
| 18 | + - [3.1.10 useDebugValue](#3110-usedebugvalue) |
| 19 | + - [3.1.11 훅의 규칙](#3111-훅의-규칙) |
| 20 | + - [3.1.12 정리](#3112-정리) |
| 21 | + - [3.2 사용자 정의 훅과 고차 컴포넌트 중 무엇을 써야 할까?](#32-사용자-정의-훅과-고차-컴포넌트-중-무엇을-써야-할까) |
| 22 | + - [3.2.1 사용자 정의 훅](#321-사용자-정의-훅) |
| 23 | + - [3.2.2 고차 컴포넌트](#322-고차-컴포넌트) |
| 24 | + - [3.2.3 사용자 정의 훅과 고차 컴포넌트 중 무엇을 써야 할까?](#323-사용자-정의-훅과-고차-컴포넌트-중-무엇을-써야-할까) |
| 25 | + - [3.2.4 정리](#324-정리) |
| 26 | + |
| 27 | +<br> |
| 28 | + |
| 29 | +## 3.1 리액트 훅 깊게 살펴보기 |
| 30 | + |
| 31 | +### 3.1.1 useState |
| 32 | +- 렌더링에 사용할 변수와 그 변수를 변경하는 함수를 제공하는 훅 |
| 33 | +```javascript |
| 34 | +const [state, setState] = useState(initialState) |
| 35 | +``` |
| 36 | +- 변수에 직접 할당하지 않고 이런 훅을 사용하는 이유는? |
| 37 | + - 리액트에서 렌더링은 함수형 컴포넌트의 return과 클래스형 컴포넌트의 render 함수를 실행한 다음 이 실행 결과를 이전의 리액트 트리와 비교해 렌더링이 필요한 부분만 업데이트 하기 때문. |
| 38 | + - 즉, 변수에 할당하면 변경 사항이 생겨도 컴포넌트 리렌더링이 일어나지 않음. |
| 39 | +- 매번 렌더링이 발생할 때마다 함수는 다시 새롭게 실행된다. |
| 40 | +- setState 내부에서 state를 클로저를 이용해 유지한다. |
| 41 | +- 게으른 초기화 |
| 42 | + - useState에 함수를 초기값으로 넣으면 한번만 실행해 할당하고 리렌더링시 함수는 무시된다. |
| 43 | + - 무거운 연산 등의 초기값을 함수로 사용함이 적합하다. |
| 44 | + |
| 45 | +### 3.1.2 useEffect |
| 46 | +```javascript |
| 47 | +useEfect(() => {...}, [props, state]); |
| 48 | +``` |
| 49 | +- 두 번째 인자로 전달하는 배열을 의존성 배열이라고 한다. |
| 50 | +- 의존성 배열에 변경이 일어나면 첫번째 전달 인자인 함수가 실행된다. |
| 51 | +- 의존성 배열에 빈 배열을 입력한 경우 |
| 52 | + - 리액트는 이 useEffect는 비교할 의존성이 없다고 판단해 최초 렌더링 직후에 함수를 실행하고 그 이후에는 실행되지 않는다. |
| 53 | +- 의존성 배열에 암런 값도 전달하지 않는다면 |
| 54 | + - 이 때는 의존성을 비교할 필요가 없다고 판단해 렌더링 할 때마다 실행된다. |
| 55 | +- useEffect에서 비동기 처리가 필요하다면 비동기 처리로 인한 경쟁상태를 방지하기 위해 동기 함수로 감싸서 처리한다. |
| 56 | + |
| 57 | +### 3.1.3 useMemo |
| 58 | +- 비용이 큰 연산에 대한 결과를 저장해 두고 이 저장된 값을 반환하는 훅 |
| 59 | +```javascript |
| 60 | +const memoizedValue = useMemo(() => expansiveComputation(a, b), [a, b]); |
| 61 | +``` |
| 62 | +- 첫번째 인수로는 어떠한 값을 반환하는 생성함수를, 두 번째 인수로른 해당 함수가 의존하는 값의 배열을 전달 |
| 63 | +- useMemo는 렌더링 발생 시 의존성 배열의 값이 변경되지 않았으면 함수를 재실행하지 않고, 이전에 기억해 둔 값을 반환하고, 의존성 배열의 값이 변경되었다면 첫번째 인수의 함수를 실행한 후에 그 값을 반환하고 그 값을 다시 기억해 둔다. |
| 64 | +- 단순히 값 뿐만 아니라 컴포넌트도 memoization 가능하다. |
| 65 | +- 의존성으로 선언된 값이 변하지 않는한 다시 수행되지 않으므로 무거운 연산에 사용이 적합 |
| 66 | + |
| 67 | +### 3.1.4 useCallback |
| 68 | +- 값의 메모이제이션을 위해 useMemo를 사용했다면, 함수의 메모이제이션을 위해 사용하는 것이 useCallback 훅 |
| 69 | +- 첫번째 인수로 함수를, 두 번째 인수로 의존성 배열을 전달하면, useMemo와 마찬가지로 의존성 배열이 변경되지 않는 한 함수를 재생성하지 않는다. |
| 70 | +- useMemo와 useCallback의 유일한 차이는 메모이제이션하는 대상이 변수냐 함수냐일 뿐이다. |
| 71 | + |
| 72 | +### 3.1.5 useRef |
| 73 | +- 컴포넌트가 렌더링 될 때만 생성되며, 컴포넌트 인스턴스가 여러개라도 각각 별개의 값을 바라본다. |
| 74 | +- useRef의 최초 기본값은 return 문에 정의해둔 DOM이 아니고 useRef()로 넘겨받은 인수이다. |
| 75 | +- 원하는 시점의 값을 렌더링에 영향을 미치지 않고 보관해 둘 때 사용 |
| 76 | + - e.g.) usePrevious |
| 77 | + |
| 78 | +### 3.1.6 useContext |
| 79 | +- 상태를 주입하는 기능 |
| 80 | +- 자식 컴포넌트에 전달할 값을 외부에 정해두고 사용하는 방식 |
| 81 | +```typescript |
| 82 | +const context = createContext<{hello:string} | undefined>() |
| 83 | +useContext(context) |
| 84 | +``` |
| 85 | +- 유의점: useContext가 선언돼 있으면 provider에 의존성을 가지게 된다. |
| 86 | + |
| 87 | +### 3.1.7 useReducer |
| 88 | +- useState 심화버전 |
| 89 | +- state를 관리하는 것은 일반적으로 useState로도 충분하지만 state 하나가 가져야 할 값이 복잡하고 이를 수정하는 경우의 수가 많아진다면 state 관리가 어려워진다. |
| 90 | +- useReducer를 사용해 state를 관리하면 state를 사용하는 로직과 이를 관리하는 비지니스 로직을 분리할 수 있어 state를 관리하기가 한결 쉬워진다. |
| 91 | +- 반환값은 state와 state를 업데이트하는 함수이다. setState는 값을 넘겨주지만 여기서는 state를 변경할 수 있는 액션을 넘겨준다. |
| 92 | +- useState의 인수와 달리 2개에서 3개의 인수를 필요로한다. 첫번째 인수는 기본 액션, 두번째 인수는 초기값, 세번째 인수는 게으른 초기화를 사용할 때 사용되며, 선택적 인수이다. 세번째 인수인 함수는 두번째 인수를 인자로 사용한다. |
| 93 | + |
| 94 | +### 3.1.8 useImperativeHandle |
| 95 | +- 부모에게서 넘겨받은 ref를 원하는대로 수정할 수 있는 훅 |
| 96 | +- 원래 ref는 {current:<HTMLElement>}와 같은 형태로 HTMLElement만 주입할 수 있는 객체였다. 여기서는 전달받은 ref에다 useImperativeHandle 훅을 사용해 추가적인 동작을 정의했다. 이로써 부모는 단순히 HTMLElement 뿐만 아니라 자식 컴포넌트에서 새롭게 설정한 객체의 키와 값에 대해서도 접근할 수 있게 됐다. |
| 97 | +- useImperativeHandle을 사용하면 이 ref의 값에 원하는 값이나 액션을 정의할 수 있다. |
| 98 | +- forwardRef |
| 99 | + - ref를 전달하는데 있어서 일관성을 제공하기 위함 |
| 100 | + - 자식 컴포넌트에 ref를 전달할 때 명확히 하여 개발에 편리함을 꾀하기 위함 |
| 101 | + |
| 102 | + |
| 103 | +### 3.1.9 useLayoutEffect |
| 104 | +- useEffect와 동일하나 모든 DOM의 변경 후에 동기적으로 발생 |
| 105 | +- useLayoutEffect가 useEffect보다 먼저 실행된다 |
| 106 | +- useLayoutEffect는 브라우저에 변경사항이 반영되기 전에 실행되는 반면 useEffect는 브라우저에 변경사항이 반영된 이후에 실행된다. |
| 107 | +- 사용할 곳: DOM은 계산 됐지만 이것이 화면에 반영되기 전에 하고싶은 작업이 있을 때. |
| 108 | + |
| 109 | +### 3.1.10 useDebugValue |
| 110 | +- 디버깅 하고 싶은 정보를 이 훅에다 사용하면 리액트 개발자 도구에서 볼 수 있다. |
| 111 | +- 사용자 정의 훅 내부의 내용에 대한 정보를 남길 수 있는 훅 |
| 112 | +- 두번째 인수로 포매팅 함수를 전달하면 첫번째 인자 값이 변경됐을 때만 호출되어 포매팅된 값을 노출한다 |
| 113 | +- 오직 다른 훅 내부에서만 실행할 수 있다. |
| 114 | +- 공통 훅을 제공하는 라이브러리나 대규모 웹 애플리케이션에서 디버깅 관련 정보를 제공하고 싶을 때 유용 |
| 115 | + |
| 116 | +### 3.1.11 훅의 규칙 |
| 117 | +- 항상 훅은 실행 순서를 보장받을 수 있는 컴포넌트 최상단에 선언돼 있어야 한다. 조건문이필요하다면 반드시 훅 내부에서 수행해야 한다. |
| 118 | + |
| 119 | +### 3.1.12 정리 |
| 120 | + |
| 121 | +<br> |
| 122 | + |
| 123 | +## 3.2 사용자 정의 훅과 고차 컴포넌트 중 무엇을 써야 할까? |
| 124 | + |
| 125 | +### 3.2.1 사용자 정의 훅 |
| 126 | +- 서로 다른 컴포넌트 내부에서 같은 로직을 공유하고자 할 때 주로 사용 |
| 127 | +- use로 시작하는 이름으로 만들어야 한다. |
| 128 | +- 복잡하고 반복되는 로직을 간단하게 만드는 용도 |
| 129 | +- 내부에 다른 훅을 사용해 원하는 훅을 만드는 기법 |
| 130 | + |
| 131 | + |
| 132 | +### 3.2.2 고차 컴포넌트 |
| 133 | +- 고차함수와 동일하게 함수형 컴포넌트에서 다른 컴포넌트를 인자로 받아 컴포넌트를 반환하는 컴포넌트 |
| 134 | +- 컴포넌트 전체를 감쌀 수 있다는 점에서 사용자 정의 훅보다 더욱 큰 영향력을 컴포넌트에 미칠 수 있다. 단순히 값을 반환하거나 부수 효과를 실행하는 사용자 정의 훅과는 다르게, 고차 컴포넌트는 컴포넌트의 결과물에 영향을 미칠 수 있는 다른 공통된 작업을 처리할 수 있다. |
| 135 | +- 사용자 정의 훅이 use로 시작하는 이름을 사용했다면 리액트의 고차 컴포넌트도 마찬가지로 with로 시작하는 이름을 사용해야한다. |
| 136 | +- props로 받은 컴포넌트를 임의로 수정, 추가, 삭제하지 않아야 한다. |
| 137 | +- 여러 개의 고차 컴포넌트로 컴포넌트를 감쌀 경우 복잡성이 커진다 |
| 138 | + |
| 139 | +### 3.2.3 사용자 정의 훅과 고차 컴포넌트 중 무엇을 써야 할까? |
| 140 | +- 사용자 정의 훅이 필요한 경우 |
| 141 | + - 리액트에서 제공하는 훅으로만 공통 로직을 격리할 수 있을 때 |
| 142 | + - 훅 자체로는 렌더링에 영향을 미치지 못하므로 개발자가 훅을 원하는 방향으로만 사용 가능 |
| 143 | +- 고차 컴포넌트를 사용해야 하는 경우 |
| 144 | + - 렌더링의 결과물에도 영향을 미치는 공통 로직 |
| 145 | + |
| 146 | +### 3.2.4 정리 |
0 commit comments