Part9_Hooks
이보경
책 읽기

9.1 리액트 훅

1. useState

2. 의존성 배열을 사용하는 훅

useEffect

레이아웃 배치와 화면 렌더링이 모두 완료된 후에 실행

function useEffect(effect: EffectCallback, deps?: DependencyList): void;
type DependencyList = ReadonlyArray<any>;
type EffectCallback = () => void | Destructor;

EffectCallback에서 Promise 타입은 반환하지 않으므로 콜백함수에 비동기 함수가 들어갈 수 없다. 비동기 함수를 호출할 수 있다면 경쟁 상태를 불러일으킬 수 있다.

경쟁 상태
: 멀티스레딩 환경에서 동시에 여러 프로세스나 스레드가 공유된 자원에 접근하려고 할 때 발생할 수 있는 문제 : 실행 순서나 타이밍을 예측할 수 없게 되어 프로그램 동작이 원하지 않는 방향으로 흐를 수 있다

  • Destructor(클린업함수)
    • 빈 배열이면 컴포넌트가 마운트 해제될 때 실행하는 함수
    • 빈 배열이 아니라면 배열의 값이 변경될 때마다 실행

useLayoutEffect

화면에 컴포넌트가 그려지기(페인팅) 전에 콜백 함수를 실행

useMemo

useCallback

3. useRef

DOM을 직접 선택해야 하는 경우에 사용

  • 인풋 요소에 포커스 설정
  • 특정 컴포넌트 위치로 스크롤

useRef는 세 종류의 타입 정의를 가지고 있음

→ useRef에 넣어주는 인자 타입에 따라 반환되는 타입(MutableRefObject 또는 RefObject)이 달라짐

function useRef<T>(initialValue: T): MutableRefObject<T>; // 1.
function useRef<T>(initialValue: T | null): RefObject<T>; // 2.
function useRef<T = undefined>(): MutableRefObject<T | undefined>; // 3.
 
interface MutableRefObject<T> {
  current: T;
}
 
interface RefObject<T> {
  readonly current: T | null;
}

MutableRefObject

MutableRefObject의 current는 값을 변경할 수 있다.

만약 null을 허용하기 위해 const ref = useRef<HTMLInputElement | null>(null); 로 지정하면 첫 번째 타입 정의를 따르고, ?? MutableRefObject의 current는 변경할 수 있는 값이 되어 ref.current의 값이 바뀌는 사이드 이펙트가 발생할 수 있다.

RefObject

RefObject의 current는 값을 변경할 수 없다. (readonly)

const ref = useRef<HTMLInputElement>(null); 로 지정하면 두 번째 타입 정의를 따르게 된다. 이러면 RefObject를 반환하여 ref.current 값을 임의로 변경할 수 없게 된다.

자식 컴포넌트에 ref 전달하기

ForwardedRef에는 MutableRefObject만 들어올 수 있다.

부모 컴포넌트에서 ref를 어떻게 선언했는지와 관계없이 자식 컴포넌트가 해당 ref를 수용할 수 있다.

useImperativeHandle

ForwardRefRenderFunction과 함께 쓸 수 있는 훅 부모 컴포넌트에서 ref를 통해 자식 컴포넌트에서 정의한 커스터마이징된 메서드를 호출할 수 있다. 자식 컴포넌트는 내부 상태나 로직을 관리하면서, 부모 컴포넌트와의 결합도도 낮출 수 있다.

useRef의 여러 가지 특성

  • 값이 바뀌어도 컴포넌트의 리렌더링이 발생하지 않는다. 상태가 변경되더라도 불필요한 리렌더링을 피할 수 있다.
  • 값을 설정한 후 즉시 조회할 수 있다.
    (리액트 컴포넌트의 상태는 상태 변경 함수를 호출하고 렌더링된 이후에 업데이트한 상태를 조회할 수 있다.)

9.2 커스텀 훅