배움나눔 스터디에서 발표용으로 정리한 글입니다.
이 글은 배우면서 작성한 글이라 내용에 오류가 있을 수 있습니다!
틀린 부분이 있으면 댓글로 알려주세요!
빠른 작성을 위해 영어로 작성되었습니다.
SyncExternalStore를 사용하는 이유는 무엇입니까?
1. React 18 혁신, 동시성
React 18 발표와 함께 React 팀의 이번 릴리스 병행 의 도입으로 개선된 렌더링 엔진(자동 배치)수업 향상된 사용자 경험(전환, 서스펜스)그것에 집중했어야 했다.
동시성은 어디까지입니까?
이름에서 알 수 있듯이 순서에 관계없이 동시에 실행할 수 있는 속성입니다. 프로그래밍 언어에서 프로그램을 독립적으로 실행할 수 있는 여러 부분으로 나누어 프로그램을 구성하는 방법입니다. 여러 작업이 동시에 실행되는 것처럼 보이도록 우선 순위를 지정하는 개념으로 생각할 수 있습니다.

React 18 이전에는 렌더링이 조작할 수 없는 동기 프로세스였습니다. 렌더링이 시작되면 중지할 수 없습니다. 그러나 반응 18에서 동시 렌더링렌더링 프로세스를 일시 중지, 재개 또는 취소하기 위해 개입할 수 있습니다.
따라서 집중적인 렌더링 작업 시 다른 렌더링이 차단되는 현상을 개선하여 사용자 경험을 향상시킬 수 있습니다.
예: 시작 전환
React 18에서 업데이트는 다음과 같이 나뉩니다.
- 긴급 업데이트 : 탭, 클릭, 누르기 등 직접적인 상호작용 반영
- 전환 업데이트 : UI 전환
탭, 클릭, 누름과 같은 긴급 업데이트는 빠르게 업데이트되지 않으면 지연되고 앱이 이상하게 느껴질 수 있습니다. 그러나 화면은 결과가 즉시 나타날 것으로 기대하지 않으므로 전환이 느리게 업데이트되어도 괜찮습니다.
import { startTransition } from 'react';
// 긴급한 업데이트 : 입력하고 있는 값
setInputValue(input);
// startTransition으로 래핑된 업데이트는 긴급하지 않은 것으로 처리되고, 더 긴급한 업데이트가 들어오면 중단된다.
startTransition(() => {
// 전환 업데이트: 입력값에 따른 쿼리값
setSearchQuery(input);
});
위와 같이 startTransition에 래핑된 업데이트는 전환 업데이트로 취급되며 긴급 업데이트가 도착하면 일시 중지됩니다.
차단 렌더링 문제를 해결하기 위해 startTransition을 사용하는 예
2. 혁신이 만들어낸 문제?!
반응 시스템 내에서 훌륭합니다. 그러나 외부 저장소를 사용하거나 의존하는 라이브러리의 경우 눈물 문제가 발생합니다.
외부 저장소 대 내부 저장소

- 내부 매장(states) : React, useState, useReducer, context, props 등에서 제공하는 상태 관리 도구 또는 저장소
- 외부 매장
- React에서 제공하는 상태 관리 API 외에 상태 관리 라이브러리(mobx, redux, recoil, staat 등)
- Dom Object, Web API(날짜) 등
- ref에서 관리하는 변수 값
비동기 렌더링과 동시 렌더링 – 눈물이란 무엇입니까?

- React의 렌더링 작업이 시작됩니다. 외부 저장소에 액세스하여 색상 값을 검색하고 렌더링합니다.
- 계속 렌더링 외부 메모리는 여전히 동일한 값을 가집니다.
- 모든 구성 요소는 파란색으로 렌더링되며 일관성 있게 보입니다.
- 렌더링 후 외부 저장소를 업데이트할 수 있습니다. React는 렌더링이 완료된 후 다른 작업을 허용하므로 React가 렌더링을 하지 않는 상태에서 스토어를 업데이트하면 다음에 React가 트리를 렌더링할 때 첫 번째 단계에서 다시 시작하여 모든 구성 요소가 동일한 값을 갖게 됩니다.

동시 렌더링을 통해 React는 작업이 완료되기 전에 완료하고 긴급한 작업에 양보할 수 있습니다. 이를 통해 사용자는 페이지를 차단하지 않고 페이지와 상호 작용할 수 있습니다.
그렇다면 두 번째 단계가 사용자가 상점을 파란색에서 빨간색으로 변경하는 버튼을 누르는 것이라면 어떨까요?
가장 먼저 렌더링되는 컴포넌트는 파란색 값을 받지만 중간 이후부터는 사용자의 빠른 인터랙션을 반영하기 위해 먼저 처리되어 빨간색으로 표시되어 시각적인 불일치가 발생합니다. 이 현상을 티어링이라고 합니다.
눈물 예 – 참조
그 찢어짐을 해결하고 안전하고 일관되게 외장 스토리지의 가치를 활용하기 위해 나왔습니다. useSyncExternalStore BE!!!
useSyncExternalStore 쉬운 사용법

useSyncExternalStore는 테어링 문제 없이 외부 저장소를 구독할 수 있는 반응 후크입니다.
두 개의 필수 매개변수와 하나의 선택적 매개변수를 취하여 getSnapshot의 결과인 Snapshot(상태 값)을 반환합니다.
매개변수
- Subscribe: 콜백 인자(onStoreChange)를 받아 스토어를 구독하는 함수. 비즈니스가 변경되면 제공된 콜백을 호출합니다. 이렇게 하면 구성 요소가 다시 렌더링됩니다. 구독을 정리하는 함수를 반환해야 합니다.
- getSnapshot : 구성 요소에 필요한 메모리 데이터의 스냅샷을 반환하는 함수입니다. 메모리가 변경되지 않는 한 getSnapshot에 대한 반복 호출은 동일한 값을 반환해야 합니다. 메모리가 변경되어 반환 값이 다른 경우(object.is) 구성 요소를 다시 렌더링합니다.
- getServerSnapshot : 메모리에 있는 데이터의 초기 스냅샷을 반환하는 함수입니다. 서버 렌더링 중에 클라이언트에서 서버 렌더링 콘텐츠를 수화하는 동안 사용됩니다. 서버 스냅샷은 클라이언트와 서버 간에 동일해야 하며 일반적으로 직렬화되어 서버에서 클라이언트로 전파됩니다. 이 기능이 제공되지 않으면 서버에서 렌더링이 실패합니다. ⇒ SSR용 기능
예: TodoList 스토어
하지만 동시성 기능을 사용하지 않습니까?
또한 동시성 렌더링은 향후 React의 주요 축이기 때문에 언제, 어디서, 어떻게 동시성 기능이 추가될지 모르기 때문에 내 코드가 언제 문제가 될지 예측할 수 없습니다.
그래서 죠타이와 주 개발자인 가토 다이시씨는 외부 저장소와 내부 저장소의 명확한 구분따라서 외부 저장소 데이터를 참조하는 코드는 useSyncExternalStore를 적극적으로 사용하는 것이 좋습니다.
(특히 라이브러리 개발자 입장에서는 사용자가 동시성 지원 여부를 선택할 수 있기 때문에 이는 거의 필수적입니다.)
Zero Parallelism이 적용되지 않더라도 주관적인 생각결과적으로 useSyncExternalStore 후크는 배경을 제거하고 함수 자체만 남겨두면 React에서 특정 데이터를 구독한 후 다시 렌더링을 트리거할 수 있는 후크입니다. 이것이 개발자가 더 자유롭게 특정 시점에 재렌더링을 트리거할 수 있는 새로운 방법이 아닐까요?
또한 이 훅을 사용하면 특정 값만 참조하는 스냅샷 기능을 구현함으로써 컨텍스트 API를 통해 복잡한 상태 값을 전체적으로 참조함으로써 발생하는 불필요한 리렌더링 문제를 줄일 수 있다. → 현재 cos-ui form 신청 중
이전에는 이러한 로직을 useState, useEffect로 다소 번거롭게 구현해야 했지만, 이제 subscribe 기능이 잘 구현되면 useSyncExternalStore로 해결할 수 있습니다. 그러면 코드가 더 읽기 쉬워지지 않을까요?
useSyncExternalStore의 또 다른 예
- useSyncExternalStore – 과소평가된 반응 API
- 상태 등의 Global State Management 관리 기능 구현
참고문헌
문서에 응답: useSyncExternalStore : React Docs useSyncExternalStore 공식 문서
응답 컨퍼런스 2021: 외부 저장소 라이브러리에 대해 응답 18 : 국영 개발자 카토 다이시 발표 영상
https://velog.io/@jay/useSyncExternalStore
