본문 바로가기

리액트 공식 문서 읽기

32화: useSyncExternalStore

이 글은 단순히 리액트 공식 문서를 읽고 베꼈을 뿐이다!! 학습 목적이라면 공식 문서를 보는 걸 추천한다.

 

참새 한 쌍. Unsplash 에 Ray ZHUANG 님이 올림

공식 문서

https://react.dev/reference/react/useSyncExternalStore

 

useSyncExternalStore – React

The library for web and native user interfaces

react.dev

useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot?)

  • 외부 저장소와의 동기화를 도와주는 리액트 훅
  • 반환값: 저장소에 있는 데이터의 snapshot
  • subscribe
    • 인자로 '구독자' 하나를 받는 콜백 함수
    • 외부 저장소의 '구독자 목록'에 '구독자'를 추가하는 기능 필요
    • 반환값: 해당 '구독자'를 '구독자 목록'에서 제거하는 인자 없는 콜백 함수
    • 이 '구독자'는 일종의 함수: 외부 저장소의 값을 변경한 후 외부 저장소에서는 이 구독자를 호출하여 snapshot을 다시 받아가야 한다는 것을 알려줘야 함
  • getSnapshot
    • 외부 저장소에 저장된 값의 snapshot을 반환하는 함수
    • 외부 저장소가 바뀌지 않았다면 몇 번 불러도 같은 값을 반환해야 함
    • 반환한 값이 Object.is로 비교했을 때 변하면 리렌더링
  • getServerSnapshot (optional)
    • 서버에서 컴포넌트를 렌더링할 경우에 사용
    • 외부 저장소의 초기 스냅샷을 반환하는 함수
  • getSnapshot의 반환값은 바꿀 수 없어야(immutable) 함. 만약 외부 저장소의 값이 변할 수 있(mutable)다면 값이 바뀌었을 때 새로운 immutable snapshot을 반환해야 함. 만약 바뀌지 않았으면 캐싱된 이전 snapshot을 반환해야 함.
  • 리렌더링 시 다른 구독 함수를 넘겨주면 다시 구독함. 이게 싫으면 구독 함수의 정의를 컴포넌트 밖에서 해야 함.

사용법

외부 저장소 구독하기

  • 대부분의 컴포넌트는 props, state, context로부터 본인이 필요한 정보들을 받음
  • 하지만 가끔씩 컴포넌트는 리액트 외부의 저장소에서 값을 읽어올 필요도 있음
    • 리액트 외부의 제삼의 상태 관리 라이브러리
    • 변하는 값에 접근할 수 있고 그 값의 변화를 구독할 수 있는 브라우저 API
  • 가능하다면 리액트에 내장된 useStateuseReducer를 사용하는 것을 추천함
  • useSyncExternalStore는 이미 존재하는 리액트가 아닌 코드들과 연동하는 데 쓰기 좋음

브라우저 API 구독하기

  • 브라우저의 어떤 변하는 값을 구독하고 싶을 때
  • navigator.onLine을 구독해서 인터넷 연결 상태가 바뀌었을 때 컴포넌트를 리렌더링시킬 수 있음

로직을 커스텀 훅으로 분리하기

  • 일반적으로 컴포넌트에서 직접 useSyncExternalStore를 부르지 않음
  • 대신 특정한 대상을 구독하여 snapshot을 반환받는 로직으로 이루어진 커스텀 훅을 만들고 그걸 쓰는 게 일반적

서버에서 컴포넌트를 렌더링할 경우

  • 서버에서 컴포넌트를 렌더링하면 브라우저 외부 환경에서 초기 HTML을 만든다는 뜻
  • 브라우저에서만 사용할 수 있는 API를 쓴다면 작동하지 않음
  • 제삼의 저장소를 사용한다면 이 저장소의 값이 서버와 클라이언트 두 곳에서 모두 동일하게 만들어야 함
  • getServerSnapshot을 이용해서 서버 렌더링에서 사용할 초기값 지정 가능

문제 해결하기

The result of getSnapshot should be cached 오류가 떠요

  • getSnapshot이 매 호출마다 새로운 객체를 반환한다는 뜻(메모리 주소가 다르다는 뜻)
  • 리액트는 이 함수를 쓴 후 이전의 값과 Object.is로 비교해서 다르면 리렌더링함
  • 우리가 기존에 useState에서 상태를 바꿀 때 객체를 교체(replace)해서 리렌더링 시켰는데 근본적으로 같은 이유임
  • 외부 저장소는 이전 snapshot을 그대로 기억했다가 만약 저장소가 바뀌지 않았으면 완전 똑같은 snapshot을 돌려줘야 함

제 구독 함수가 리렌더링될 때마다 호출돼요

  • 컴포넌트의 렌더링 과정 내에 구독 함수를 정의하는 경우임
  • 렌더링할 때마다 새로운 주소를 가진 구독 함수가 만들어지므로 계속 구독하는 셈
  • 정 컴포넌트 안에서 정의해야겠으면 useCallback 쓰기

'리액트 공식 문서 읽기' 카테고리의 다른 글