본문 바로가기
Programming/13. Book

모던 리액트 Deep Dive - 10장

by @sangseophwang 2024. 3. 2.

리액트 17 버전 살펴보기

리액트 16 모듈은 promise로 lazy하게 불러와서 호환성 유지

  • 17 내부에서 16 모듈을 렌더링
  • 하나의 웹 사이트에 16, 17버전이 공존하는 방식

이벤트 위임 방식의 변경

  • click 이벤트에 일반 핸들러가 아닌 ref로 제어하게 되면 click이 아닌 noop라는 핸들러 추가
  • 하지만 동일하게 동작하는데, 그 이유는 이벤트 타입당 하나의 핸들러를 루트에 부착하는 이벤트 위임 방식을 사용하기 때문이다.
  • 16까지는 document에 연결했지만, 17부터는 리액트 컴포넌트 최상단 트리로 변경됐다.
    • document에 이벤트가 부착되면 이벤트 전파를 막을 수 없게 돼 이벤트 버블링에 혼선이 생기기 때문이다.
    • 그래서 16에서는 document - 루트 사이에 stopPropagation을 적용하면 모든 핸들러가 동작하지 않게 된다.

import React from ‘react’ 제거

  • 위 구문은 JSX를 JS로 변환하는 과정에 필요한 구문이었다.
  • 이 구문을 제거함으로써 번들 사이즈를 조금이나마 줄일 수 있게 됐다.

이벤트 풀링 제거

  • 리액트에서는 브라우저 기본 이벤트를 래핑하는 SyntheticEvent라는 이벤트가 있는데, 이벤트의 주기적 해제 처리를 위해 존재했던 기능이었다.
  • 이벤트 풀링 시스템 동작 방식
    • 이벤트 핸들러가 이벤트 발생
    • 합성 이벤트 풀에서 합성 이벤트 객체에 대한 참고 가져오기
    • 이벤트 정보를 합성 이벤트 객체에 넣기
    • 유저가 지정한 이벤트 리스너 실행
    • 이벤트 객체 초기화
  • event에 접근할 때 SyntheticEvent가 null로 초기화하기 때문에 비동기 코드에서 사용할 때는 persist를 추가해줘야 했다.
  • 따라서 이런 별도 메모리 공간에 합성 이벤트 객체를 할당하는 방식은 17부터 제거됐다.

useEffect 클린업 함수의 비동기 실행

  • 17부터는 클린업 함수는 컴포넌트의 커밋 단계가 완료될 때까지 지연된다. 즉, 화면이 업데이트가 완전히 끝난 이후 실행하도록 바뀌었다.
  • 이로 인해 화면 업데이트 시간이 조금 단축됐다.

리액트 18 버전 살펴보기

새로 추가된 훅

  • useId
    • math.random()은 서버 렌더링 - 하이드레이션 시 값이 다르다.
    • 따라서 useId로 클라이언트 - 서버 불일치를 피하면서 컴포넌트 내 고유값을 생성할 수 있다.
    • useId 생성값은 : 로 감싸져 있는데, 이는 CSS 선택자나 querySelector에서 작동하지 않도록 하기 위함이다.
  • useTransition
    • UI 변경을 가로막지 않고 상태를 업데이트할 수 있는 훅
    • 이를 활용하면 상태 업데이트를 긴급하지 않은 것으로 간주해 무거운 렌더링 작업을 조금 미룰 수 있다.
    • 비동기 렌더링 가능! (동시성)
    • startTransition 내부는 반드시 setState와 같은 상태 업데이트 함수와 관련된 작업만 넘길 수 있다.
    • 타이핑으로 인해 setState가 일어나는 경우 타이핑이 끝날 때까지 useTransition으로 지연시킨 상태 업데이는 일어나지 않는다 (동기 상태 업데이트로 인한 실행 지연)
    • startTransition에 넘겨주는 함수는 반드시 동기 함수여야 한다.
  • useDeferredValue
    • 리액트 컴포넌트 트리에서 리렌더링이 급하지 않은 부분을 지연할 수 있게 도와주는 훅
    • 디바운스와 비슷하지만, 디바운스는 고정된 지연 시간이 필요한 반면 고정된 지연 없이 첫 번째 렌더링이 완료된 이후에 지연된 렌더링을 수행한다.
    • 그러므로 지연된 렌더링은 중단할 수도 있으며, 사용자의 인터랙션을 차단하지도 않는다.
    • useDefferedValue는 state 값 자체만을 감싸서 값 업데이트 후 렌더링을 실행한다.
  • useSyncExternalStore
    • 테어링(tearing) 현상
      • 하나의 state 값이 있음에도 서로 다른 값(보통 state나 props 이전과 이후)을 기준으로 렌더링되는 현상
    • useTransition, useDeferredValue 훅처럼 렌더링을 일시 중지하거나 뒤로 미루는 등의 최적화가 가능해지면서 동시성 이슈가 발생할 수 있다.
    • 이로 인해 같은 데이터 소스를 바라보고 있음에도 업데이트 과정에서 서로 다른 데이터를 기준으로 렌더링하는 현상일 발생할 수 있다. 특히 리액트 외부 데이터 소스 (글로벌 변수, document, body, 외부 상태 관리 라이브러리 등)가 해당된다.
    • 구조
      • subscribe: 첫 번째 인수. 콜백 함수를 받아 스토어에 등록하는 용도. 스토어 값이 변경되면 이 콜백이 호출되고, 이 훅을 사용하는 컴포넌트를 리렌더링한다.
      • getSnapshot: 두 번째 인수. 현재 스토어의 데이터를 반환하는 함수.
      • 마지막 인수는 옵셔널 값. SSR 시 내부 리액트를 하이드레이션하는 도중에만 사용
  • useInsertionEffect
    • css-in-js 라이브러리를 위한 훅
    • DOM이 실제로 변경되기 전에 동기적으로 실행
    • 즉, 브라우저가 레이아웃을 계산하기 전에 실행될 수 있게끔 해서 자연스러운 스타일 삽입 가능
    • useInsertionEffect > useLayoutEffect > useEffect
    • 실제 애플리케이션 코드에서는 가급적 사용하지 않는 것을 리액트에서 권고

react-dom/client

  • reder → createRoot
  • hydrateRoot: 하이드레이션을 위한 새로운 메서드

react-dom/server

  • renderToPipeableStream
    • 스트림을 지원하는 메서드 (Node.js 환경)
    • HTML 점진적 렌더링, 클라이언트에서는 중간에 script 삽입 등의 작업 가능
    • 이를 통해 서버에서는 suspense를 사용해 렌더링이 빠르게 필요한 곳은 먼저 렌더링하고, 값비싼 연산으로 구성된 부분은 이후에 렌더링되게끔 할 수 있다.
  • renderToReadableStream
    • 웹 스트림을 기반으로 작동

Automatic Batching

  • 여러 상태 업데이트를 하나의 리렌더링으로 묶어서 성능 향상
  • 동기, 비동기 모두 한 번만 렌더링되도록 개선

더욱 엄격해진 엄격 모드

  • 엄격 모드는 리액트에서 제공하는 컴포넌트 중 하나로, 리액트 앱에서만 발생할 수 있는 잠재적 버그를 찾는 데 도움이 된다.
  • 리액트 18에서는 개발 모드에서 출력되는 두 번째 console.log는 회색으로 표시하게끔 변경됐다.
  • 엄격해진 목록
    • 더 이상 안전하지 않는 특정 생명주기를 사용하는 컴포넌트에 대한 경고 (UNSAFE_)
    • 문자열 ref 사용 금지
    • findDOMNode에 대한 경고 출력
    • getChildContext 사용
    • 예상치 못한 side effect 검사

Suspense 기능 강화

  • 기존의 Suspense는 컴포넌트가 아직 보이기도 전에 useEffect가 실행되는 문제가 있었다.
  • Suspense는 서버에서 사용할 수 없었다.
  • 18에서는 이 두 문제가 해결됐으며, 추가로 Suspense 내 스로틀링이 추가됐다.

그 외

  • 컴포넌트에서 명시적으로 null 리턴해주지 않아도 에러가 발생하지 않는다. (undefined)]
반응형

'Programming > 13. Book' 카테고리의 다른 글

리팩터링 - 2장  (0) 2024.03.02
모던 리액트 Deep Dive - 11장  (0) 2024.03.02
모던 리액트 Deep Dive - 5장  (0) 2024.03.02
모던 리액트 Deep Dive - 4장  (0) 2024.03.02
모던 리액트 Deep Dive - 3장  (0) 2024.03.02

댓글