본문 바로가기
Programming/13. Book

모던 리액트 Deep Dive - 3장

by @sangseophwang 2024. 3. 2.

 

리액트 훅

useState

  • 초기값이 없으면 undefined다.
  • 변경된 return 값으로 리렌더링을 실행시킨다.
  • 클로저를 사용해 함수 실행이 종료된 후에도 지역변수인 state를 참조할 수 있도록 한다.
  • useState는 useReducer로 구현되어 있다.
  • initialValue에 함수를 넣으면 초기 렌더링 이후 재실행되지 않는다. → 무거운 연산 시 사용

useEffect

  • state, props의 변화 속에서 일어나는 렌더링 과정에서 실행되는 부수 효과 함수
  • 클린업 함수로 이전에 등록했던 이벤트 핸들러를 제거해야 한다.
  • useEffect는 컴포넌트 렌더링 완료 이후 실행한다. (CSR) 반면 직접 실행은 렌더링 도중 실행된다.
    • 따라서 직접 실행은 SSR의 경우 서버에서도 실행된다.
  • useEffect는 가볍게 만들어야 한다. (관리 차원)
  • useEffect의 인수로 비동기 함수를 지정할 수 없지만, 비동기 함수 실행 자체는 가능하다.
    • 대신 클린업 함수에서 비동기 함수 실행, 생성의 반복을 막기 위해 트리거 추가 필요

useMemo

  • 의존성 배열 값의 변경 여부에 따라 값 재사용 or 재연산
  • 어떠한 값을 계산할 때 해당 값을 연산하는데 비용이 많이 든다면 사용 추천

useCallback

  • 특정 함수를 새로 만들지 않고 재사용

useRef

  • useRef는 반환값인 객체 내부에 있는 current로 값에 접근, 변경할 수 있다.
  • useRef는 그 값이 변하더라도 렌더링을 발생시키지 않는다.
  • 컴포넌트가 렌더링될 때만 생성. 컴포넌트 인스턴스가 여러 개라도 각각 별개의 값을 바라본다.

useContext

  • Context를 사용하면 명시적인 props 전달 없이도 선언한 하위 컴포넌트 모두에서 자유롭게 값 사용 가능
  • Provider wrapper로 감싸 하위 컴포넌트에서 사용

useReducer

  • 복잡한 상태값을 미리 정의해 놓은 시나리오에 따라 관리 가능
  • useReducer, useState 모두 클로저를 활용해 값을 가둬서 state를 관리한다.
// 이렇게 토글 형식으로도 쓸 수 있다.

const [value, toggleValue] = React.useReducer(previous => !previous, true)

<button onClick={toggleValue}>Toggle</button>
// useReducer로 useState 구현하기

const useStateReducer = (prevState, newState) =>
  typeof newState === 'function' ? newState(prevState) : newState

const useStateInitializer = initialValue =>
  typeof initialValue === 'function' ? initialValue() : initialValue

function useState(initialValue) {
  return React.useReducer(useStateReducer, initialValue, useStateInitializer)
}

useImperativeHandle

  • forwardRef : 하위 컴포넌트에서 부모 컴포넌트의 ref를 사용하고 싶을 때 사용
    • 컴포넌트를 forwardRef로 감싸고 두번째 인수로 ref 전달
  • useImperativeHandle을 부모에게서 넘겨받은 ref를 원하는대로 수정할 수 있는 훅이다.

useLayoutEffect

  • 실행 순서
    • 리액트가 DOM 업데이트
    • useLayoutEffect 실행
    • 브라우저에서 변경 사항 반영
    • useEffect 실행
  • useLayoutEffect가 실행 종료된 다음 화면을 그린다.
    • DOM은 계산됐지만 이것이 화면에 반영되기 전에 하고 싶은 작업이 있을 때와 같이 반드시 필요할 때만 사용해야 한다.
    • DOM 요소를 기반으로 한 애니메이션, 스크롤 위치 제어 등

useDebugValue

  • 개발 과정에서 사용하는 훅
  • 사용자 정의 훅 내부의 내용에 대한 정보를 남길 수 있는 훅

그 외 흥미로운 훅

  • useInsertionEffect
    • CSS-in-JS 라이브러리 작성자를 위한 훅
    • DOM 변이 전에 실행
    • 클라이언트에서만 실행
import { useInsertionEffect } from 'react';

// Inside your CSS-in-JS library
// CSS-in-JS 라이브러리 내부에서
function useCSS(rule) {
  useInsertionEffect(() => {
    // ... inject <style> tags here ...
    // ... <style> 태그를 여기에 주입합니다.
  });
  return rule;
}
  • useId
    • 접근성 속성에 전달할 수 있는 고유한 ID를 생성하는 훅
import { useId } from 'react';

function PasswordField() {
  const passwordHintId = useId();
  return (
    <>
      <label>
        Password:
        <input
          type="password"
					
					// 동일한 id 내용을 스크린리더에서 사용
          aria-describedby={passwordHintId}
        />
      </label>
      <p id={passwordHintId}>
        The password should contain at least 18 characters
      </p>
    </>
  );
}

export default function App() {
  return (
    <>
      <h2>Choose password</h2>
      <PasswordField />
      <h2>Confirm password</h2>
      <PasswordField />
    </>
  );
}

사용자 정의 훅 vs 고차 컴포넌트

  • 사용자 정의 훅
    • useState와 같은 훅을 사용해 원하는 훅을 만드는 기법
    • 반복되는 로직과 그에 따른 상태 분리
    • use-
  • 고차 컴포넌트 (HOC, Higher Order Component)
    • 컴포넌트 자체의 로직 재사용
    • React.memo
      • props의 변경만을 감지해 재렌더링 (state의 변경은 감지 x
    • 고차 함수
      • 함수를 인수로 받거나 결과로 반환하는 함수
    • 컴포넌트로 컴포넌트를 감싸서 중간에서 비즈니스 로직 수행 후 그에 따른 컴포넌트 반환
    • with-

커스텀 훅

useMedia

  • 미디어 쿼리 상태 훅
// 코드
import { useState, useEffect } from 'react';

function useMedia(query) {
  const [matches, setMatches] = useState(() => window.matchMedia(query).matches);

  useEffect(() => {
    const mediaQuery = window.matchMedia(query);
    const updateMatches = () => setMatches(mediaQuery.matches);

    mediaQuery.addListener(updateMatches);
    updateMatches();

    return () => {
      mediaQuery.removeListener(updateMatches);
    };
  }, [query]);

  return matches;
}

// 활용 예시
const isMobile = useMedia('(max-width: 768px)');

createMemo

  • useMemo + 팩토리
import {createMemo} from 'react-use';

const fibonacci = n => {
  if (n === 0) return 0;
  if (n === 1) return 1;
  return fibonacci(n - 1) + fibonacci(n - 2);
};

const useMemoFibonacci = createMemo(fibonacci);

const Demo = () => {
  const result = useMemoFibonacci(10);

  return (
    <div>
      fib(10) = {result}
    </div>
  );
};

swr

  • 훅으로 구성된 데이터 페칭 라이브러리
반응형

댓글