React Version 18
1. Automatic batching
2. Suspense on the server
3. New APIs for app and library developers
4. Transition
배칭(batching)은 업데이트 대상이 되는 상태값들을 하나의 그룹으로 묶어서 한번의 리렌더링에 업데이트가 모두 진행될 수 있게 해주는 것을 의미한다.
한 함수 안에서 setState를 아무리 많이 호출시키더라도 리렌더링은 단 한번만 발생한다.
아래 코드를 살펴보면, setState함수가 2개가 있어서 원래는 리렌더링이 2번 되어야하지만, 이 setState들을 하나의 그룹으로 묶어서 1번의 리렌더링을 해준다는 것이다.
이는 함수에 끝에서 업데이트가 되며 리액트는 마지막에 1번만 리렌더링 한다. 이것은 여러 번 리렌더링을 하는것을 막기 때문에 성능을 향상시켜준다.
batch update를 사용하면 불필요한 리렌더링을 줄일 수 있어서 퍼포먼스적으로 큰 이점을 얻을 수 있는데, 이전 버전에서도 이런 batch update가 지원되었지만 클릭과 같은 브라우저 이벤트에서만 적용이 가능하고 api호출에 콜백으로 넣은 함수나 timeouts 함수에서는 작동하지 않았었다.
<api호출에 콜백으로 넣은 함수 예>
<timeouts 함수 예>
하지만 React Version 18에서는 이러한 문제가 해결되어 automatic batching을 해준다.
그러나 억지로 automatic batching을 사용하고 싶지 않을 경우도 있을 것이다.
일반적으로 일괄 처리는 안전하지만 일부 코드는 상태 변경 직후 DOM에서 무언가를 읽는데 의존할 수 있다. 이러한 사용 사례의 경우 ReactDOM.flushSync()를 사용하면 React가 억지로 바로 돔 업데이트를 하게 해준다.
즉, automatic batching이 안되고, 각각의 setState마다 리랜더링을 하게 해준다.
리액트 18 버전에서 Automatic batching은,
1. 더 나은 성능을 위한 더 적은 리렌더링을 하게 해준다.
2. 이벤트 핸들러 밖에서도 작동한다.
3. Automatic batching을 사용하고 싶지 않을 때는 ReactDOM.flushSync()를 통해서 제외할 수 있다.
리엑트의 서버사이드 렌더링은 다음의 스텝으로 이루어져 있다.
1. 서버에서 전체 앱에 대한 데이터를 가져온다.
2. 그런 다음 서버에서 전체 앱을 HTML로 렌더링하고 응답으로 보낸다.
3. 그런 다음 클라이언트에서 전체 앱에 대한 JavaScript 코드를 로드한다.
4. 그런 다음 클라이언트에서 JavaScript 논리를 전체 앱에 대해 서버 생성 HTML에 연결한다(이것이 "hydration"이다).
Hydration은 Dry한 HTML에 수분(Javascript) 공급을 하는 것이다.
핵심 부분은 다음 단계가 시작되기 전에 각 단계가 전체 앱에 대해 한 번에 완료되어야 한다는 것이다.(동기 방식 및 Waterfall 방식) 거의 모든 중요하지 않은 앱의 경우와 같이 앱의 일부가 다른 부분보다 느린 경우 이는 효율적이지 않다. 왜냐면 한페이지에 여러 컴포넌트가 있을 때 HTML 생성이 오래 걸리는 컴포넌트가 있고, 그렇지 않은 컴포넌트가 있는데 빨리 생성된 컴포넌트가 다른 컴포넌트를 위해 계속 기다려야 하기 때문에 비효율적이다.
이를 해결하기 위해 React 18의 Suspense가 있다.
React 18을 사용하면 를 사용하여 앱을 더 작은 독립 단위로 나눌 수 있다. 이 단위는 서로 독립적으로 이러한 단계를 거치며 앱의 나머지 부분을 차단하지 않는다. 결과적으로 앱 사용자는 콘텐츠를 더 빨리 보고 훨씬 빠르게 상호 작용할 수 있고, 앱에서 가장 느린 부분은 빠른 부분을 끌어내리지 않는다. 이러한 개선 사항은 자동이고, 작동하기 위해 특별한 조정 코드를 작성할 필요가 없다.
React 18에서는 업데이트 중에도 앱의 응답성을 유지하는 데 도움이 되는 새로운 API를 도입했다. 이 새로운 API를 사용하면 특정 업데이트를 "Transition"으로 표시해서 사용자 상호 작용을 크게 개선할 수 있다. React를 사용하면 상태 전환 중에 시각적 피드백을 제공하고 전환이 발생하는 동안 브라우저의 응답성을 유지할 수 있다.
이 기능은 리액트에서 어떠한 업데이트가 Urgent하며 어떠한게 그러하지 않은지 알려준다. 그래서 상태 업데이트를 하는데 우선순위를 주게 된다.
대표적으로 검색 기능을 구현할 때 검색하는 Input 은 이벤트에 따라서 리렌더링이 해당화면에 업데이트 되어야한다. 하지만 그 아래 검색 결과도 이에 따라 업데이트가 되는데 검색 결과 리스트가 많지 않더라도 내부적으로 검색 결과를 가져오는데 많은 작업을 진행할 수 있기에 검색창에 타이핑을 하는것에 따라 바로바로 검색 결과도 업데이트를 하면 성능에 문제가 생길 수 있다.
그렇기 때문에 이 부분은 검색창과 결과창 두 부분으로 나눌 수 있으며, 유저가 타이핑하는 것에 따라 즉각 반영되기를 기대하는 검색창, 그리고 검색창보다는 UI 업데이트가 느린 것에 대해 자연스럽게 받아들여져야 하는 결과창으로 나눌수 있다.
아래의 코드에서 setInputValue는 Urgent Upadates에 해당하고, setSearchQuery는 Transition Updates에 해당하는 것이다.
새로운 startTransition API는 업데이트를 "Transition"으로 표시할 수 있는 기능을 제공하여 이 문제를 해결한다. 이 API로 React에게 상태 업데이트를 하는 것에 대해 우선 순위를 정해주는 것이다.
startTransition에 래핑된 업데이트는 긴급하지 않은 것으로 처리되며 클릭이나 키 누름과 같은 더 긴급한 업데이트가 들어오는 경우 중단된다. 전환이 사용자에 의해 중단되면(예: 여러 문자를 연속으로 입력) React는 다음을 throw한다. 완료되지 않은 오래된 렌더링 작업을 제거하고 최신 업데이트만 렌더링한다.
Transition을 사용하면 UI가 크게 변경되더라도 대부분의 상호 작용을 빠르게 유지할 수 있다. 또한 더 이상 관련이 없는 콘텐츠를 렌더링하는 데 시간을 낭비하지 않아도 된다.
검색 창에 타이핑을 했을 때 startTransition API로 인해 결과 창에는 UI 업데이트 우선순위가 밀려서 업데이트 보류가 일어나게 된다. 이 때는, 아래와 같이 isPending이 true로 되기 때문에 isPending이 true일 시에 Spinner 같은 컴포넌트를 보여주면 된다.
startTransition이 없을 때는
1. State를 2개로 나눠서 따로 처리하기