@@ -401,10 +401,20 @@ memo를 하지 않았을 때 발생할 수 있는 문제
401
401
- 그리고 위 두 가지 모두가 모든 자식 컴포넌트에서 반복해서 일어남
402
402
- 리액트가 구 트리와 신규 트리를 비교
403
403
### 2.5.3 결론 및 정리
404
+
404
405
# 03. 리액트 훅 깊게 살펴보기
406
+ 함수형 컴폰넌트가 상태를 사용하거나 클래스형 컴포넌트의생명주기 메서드를 대체하는 등의 다양한 작업을 위해 hook 추가
405
407
## 3.1 리액트의 모든 훅 파헤치기
406
408
### 3.1.1 useState
407
409
함수형 컴포넌트 내부에서 상태를 정의하고, 이 상태를 관리할 수 있게 해주는 훅
410
+
411
+ 클로저를 이용하여 함수의 실행이 끝난 state에 접근하는 방식
412
+ #### 게으른 초기화
413
+ useState의 인수로 특정한 값을 넘기는 함수를 넣어줌
414
+
415
+ useState의 초깃값이 복잡하거나 무거운 연산을 포함하고 있을 때 사용 권장
416
+
417
+ 최초 렌더링 이후에는 실행되지 않고 최초의 state 값을 넣을 때만 실행
408
418
### 3.1.2 useEffect
409
419
애플리케이션 내 컴포넌트의 여러 값들을 활용해 동기적으로 부수 효과를 만드는 매커니즘
410
420
#### 클린업 함수의 목적
@@ -415,11 +425,13 @@ memo를 하지 않았을 때 발생할 수 있는 문제
415
425
- useEffect는 클라이언트 사이드에서 실행되는 것을 보장하여 내부에서 window 객체의 접근에 의존하는 코드를 사용 가능
416
426
- 컴포넌트가 렌더링되는 도중에 실행되는 직접 실행과 달리 컴포넌트의 렌더링이 완료된 이후에 실행(부수 효과)
417
427
#### useEffect의 구현
428
+ 의존성 배열은 얕은 비교로 진행
418
429
#### useEffect를 사용할 때 주의할 점
419
430
- eslint-disable-line react-hooks/exhaustive-deps 주석은 최대한 자제하라
420
- - useEffect의 첫 번째 인수에 함수명을 부여하라
431
+ - useEffect의 첫 번째 인수에 함수명을 부여하라(해당 useEffect의 목적을 파악하기 위해)
421
432
- 거대한 useEffect를 만들지 마라
422
433
- 불필요한 외부 함수를 만들지 마라
434
+ - useEffect에서 비동기로 함수를 호출할 경우 경쟁 상태가 발생할 수 있어 콜백 함수로 넣을 수 없음, 내부에서 선언하거나 즉시 실행 비동기 함수를 만들어 사용 가능
423
435
### 3.1.3 useMemo
424
436
비용이 큰 연산에 대한 결과를 저장해 두고, 이 저장된 값을 반환하는 훅
425
437
@@ -431,12 +443,29 @@ useState와 동일하게 컴포넌트 내부에서 렌더링이 일어나도 변
431
443
432
444
반환값인 객체 내부에 있는 current로 값에 접근 또는 변경할 수 있음
433
445
434
- 그 값이 변하더라도 렌더링을 하지 않음
446
+ 그 값이 변하더라도 렌더링을 하지 않음 // innerText에 useRef 객체의 current 값을 넣었을때, 값이 바뀌어도 리렌더링X
435
447
436
- useRef는 컴포넌트가 렌더링될 때만 생성되며, 컴포넌트 인스턴스가 여러 개라도 각각 별개의 값을 바라봄
448
+ useRef는 컴포넌트가 렌더링될 때만 생성되며, 컴포넌트 인스턴스가 여러 개라도 각각 별개의 값을 바라봄
449
+
450
+ 컴포넌트가 최초로 렌더링될 때는 렌더링이 반환되기 전이므로 undefined이며, useEffect를 통해 렌더링 이후에 접근 가능
451
+
452
+ 렌더링을 발생시키지 않고 원하는 상태값을 저장 가능
437
453
### 3.1.6 useContext
454
+ #### Context란?
455
+ #### Context를 함수형 컴포넌트에서 사용할 수 있게 해주는 useContext 훅
456
+ 상위 컴포넌트에서 만들어진 Context를 함수형 컴포넌트에서 사용할 수 있도록 만들어진 훅
457
+
458
+ 만약 여러 개의 Provider가 있다면 가장 가까운 Provider의 값을 가져옴
459
+
460
+ 복잡해진다면 useContext 내부에서 해당 콘텍스트가 존재하는 환경인지 확인하여 에러를 방지할 수 있음
461
+
438
462
useContext는 Context.Provider를 통해 주입된 상태를 사용할 수 있을 뿐, 그 자체로는 렌더링 최적화에 도움이 되지 않음
463
+ #### useContext를 사용할 때 주의할 점
464
+ Provider에 의존성을 가지므로 재활용이 어려워짐
465
+
466
+ props로 전달하지 않더라도 전체가 리렌더링됨(단순 주입, 렌더링 최적화에는 도움이 되지 않음)
439
467
### 3.1.7 useReducer
468
+ useState와 비슷한 형태를 띠지만 좀 더 복잡한 상태값을 미리 정의해 놓은 시나리오에 따라 관리 가능
440
469
```
441
470
// useReducer가 사용할 state를 정의
442
471
type State = {
@@ -500,9 +529,10 @@ export default function App() {
500
529
501
530
state 값을 변경하는 시나리오를 제한적으로 두고 이에 대한 변경을 빠르게 확인할 수 있게 하는 것이 목적
502
531
### 3.1.8 useImperativeHandle
503
- #### forwardRef
532
+ #### forwardRef 살펴보기
533
+ ref가 예약어이기 때문에 props로 전달할 수 없는데, 이에 일관성을 제공하기 위해서 forward로 컴포넌트를 감싸 확실하게 ref를 전달하고 안전하게 받음
504
534
```
505
- const ChildComponent = forwardRef((props, ref) => {
535
+ const ChildComponent = forwardRef((props, ref) => { // 감싸기
506
536
useEffect(() => {
507
537
// { current: undefined }
508
538
// { current: HTMLInputElement }
@@ -524,8 +554,41 @@ const ParentComponent() {
524
554
}
525
555
```
526
556
ref를 받고자 하는 컴포넌트를 forwardRef로 감싸고, 두 번째 인수로 ref를 전달받은 후, 부모 컴포넌트에서는 동일하게 props.ref를 통해 ref를 넘겨줌
527
- #### useImperativeHandle
557
+ #### useImperativeHandle이란?
528
558
부모에게서 넘겨받은 ref를 원하는 대로 수정할 수 있는 훅
559
+ ```
560
+ const Input = forwardRef((props, ref) => {
561
+ useImperativeHandle(
562
+ ref,
563
+ () => ({
564
+ alert: () => alert(props.value),
565
+ }),
566
+ [props.value],
567
+ )
568
+
569
+ return <input ref={ref} {...props} />
570
+ })
571
+
572
+ function App() {
573
+ const inputRef = useRef();
574
+ const [text, setText] = useState('');
575
+ function handleClick() {
576
+ inputRef.current.alert();
577
+ }
578
+
579
+ function handleChange(e) {
580
+ setText(e.target.value);
581
+ }
582
+
583
+ return (
584
+ <>
585
+ <Input ref={inputRef} value={text} onChange={handleChange} />
586
+ <button onClick={handleClick}>Focus</button>
587
+ </>
588
+ )
589
+ }
590
+
591
+ ```
529
592
### 3.1.9 useLayoutEffect
530
593
useEffect와 동일하나, 모든 DOM의 변경 후에 useLayoutEffect의 콜백함수 실행이 동기적으로 발생
531
594
1 . 리액트가 DOM을 업데이트
@@ -544,7 +607,17 @@ useEffect와 동일하나, 모든 DOM의 변경 후에 useLayoutEffect의 콜백
544
607
## 3.2 사용자 정의 훅과 고차 컴포넌트 중 무엇을 써야 할까?
545
608
### 3.2.1 사용자 정의 훅
546
609
### 3.2.2 고차 컴포넌트
610
+ #### React.memo란?
611
+ 리액트에서 제공하는 가장 유명한 고차 컴포넌트
612
+
613
+ state가 업데이트는 되지만 값은 같은 경우 React.memo를 통해서 변화 없음을 감지하여 이전에 기억한 컴포넌트를 그대로 반환
614
+
547
615
### 3.2.3 사용자 정의 훅과 고차 컴포넌트 중 무엇을 써야 할까?
616
+ #### 사용자 정의 훅이 필요한 경우
617
+ 리액트에서 제공하는 훅으로만 공통 로직을 격리할 수 있는 경우 사용자 정의 훅 사용
618
+
619
+ 고차 컴포넌트는 렌더링에 영향을 미치는 로직이 존재하므로 사용자 정의 훅에 비해 예측하기 어려움
620
+ #### 고차 컴포넌트를 사용해야 하는 경우
548
621
사용자 정의 훅은 그 자체로는 렌더링에 영향을 미치지 못하기 때문에 사용이 제한적이므로 반환하는 값을 바탕으로 무엇을 할지 설정 가능
549
622
550
623
렌더링의 결과물에도 영향을 미치는 공통 로직이라면 고차 컴포넌트를 사용
0 commit comments