리액트 Version 18

dev bourgeois·2023년 11월 18일

React A-Z Study

목록 보기
9/10
post-thumbnail

React Version 18

동영상

리액트 18 버전
1. 리액트 18에는 무엇이 있나요?
2. 리액트 18로 어떻게 업그레이드 할수있나요?


리액트 18 버전에 새로운 것은 무엇인가요 ?!
1. Automatic batching
2. Suspense on the server
3. New APIs for app and library developers
4. Transition

Automatic batching

참조

배칭(batching)은 업데이트 대상이 되는 상태값들을 하나의 그룹으로 묶어서 한번의 리렌더링에 업데이트가 모두 진행될 수 있게 해주는 것을 의미한다.
한 함수 안에서 setState를 아무리 많이 호출시키더라도 리렌더링은 단 한번만 발생한다.

함수에 끝에서 업데이트가 되며 리액트는 마지막에 한번만 리렌더링 한다.
이것은 여러번 리렌더링을 하는것을 막기때문에 성능상 좋은 영향을 준다.

batch update를 사용함으로 불필요한 리렌더링을 줄일 수 있어서 퍼포먼스적으로 큰 이점을 얻을 수 있는데, 이전 버전에서도 이런 batch update가 지원되었지만 클릭과 같은 브라우저 이벤트에서만 적용이 가능하고 api 호출에 콜백으로 넣은 함수나 timeouts 함수에서는 작동하지 않았다.

*batch 처리하지 않으려면 어떻게?
일반적으로 일괄 처리는 안전하지만 일부 코드는 상태 변경 직후 DOM에서 무언가를 읽는 데 의존할 수 있다. 이러한 사용 사례의 경우 ReactDOM.flushSync()를 사용하여 일괄 처리를 옵트아웃할 수 있다.

*리액트 18 버전에서 Automatic batching
1. 더 나은 성능을 위한 더 적은 리 렌더링을 한다.
2. 이벤트 핸들러 밖에서도 작동한다.
3. 필요할 때는 제외할 수 있다.


Suspense on the server(간단하게)

참조

*서버 사이드 렌더링
리엑트의 서버사이드 렌더링은 다음의 스텝으로 이뤄진다.

  1. 서버에서 전체 앱에 대한 데이터를 가져온다.
  2. 그런 다음 서버에서 전체 앱을 HTML로 렌더링하고 응답으로 보낸다.
  3. 그런 다음 클라이언트에서 전체 앱에 대한 JavaScript 코드를 로드한다.
  4. 그런 다음 클라이언트에서 JavaScript 논리를 전체 앱에 대해 서버 생성 HTML에 연결한다(이것이 "hydration").

Hydration은 ....
Dry한 HTML에 수분(Javascript) 공급을 하는 것이다.

*여기에서 문제점은 무엇?!!!

핵심 부분은 다음 단계가 시작되기 전에 각 단계가 전체 앱에 대해 한 번에 완료되어야 한다는 것이다. (동기 방식 및 Waterfall 방식) 거의 모든 중요하지 않은 앱의 경우와 같이 앱의 일부가 다른 부분보다 느린 경우 이는 효율적이지 않다.


➡️ 왜냐면 한 페이지에 여러 컴포넌트가 있을 때 HTML 생성이 오래 걸리는 컴포너트가 있고, 그렇지 않은 컴포넌트가 있는데 빨리 생성된 컴포넌트가 다른 컴포넌트를 위해서 계속 기다려야 하기 때문에 비효율적이게 된다.

*리액트 18에서 Suspense로 문제 해결하기

React 18을 사용하면 <Suspense />를 사용하여 앱을 더 작은 독립 단위로 나눌 수 있다. 이 단위는 서로 독립적으로 이러한 단계를 거치며 앱의 나머지 부분을 차단하지 않는다.
✅결과적으로 앱 사용자는 콘텐츠를 더 빨리 보고 훨씬 빠르게 상호 작용할 수 있다. 앱에서 가장 느린 부분은 빠른 부분을 끌어내리지 않믐다. 이러한 개선 사항은 자동이며 작동하기 위해 특별한 조정 코드를 작성할 필요가 없다.


Suspense on the server(자세하게)

참조

*서버 렌더링의 장점

서버 렌더링을 하지 않을 때는 자바스크립트가 로드되기 전까지는 아무것도 볼 수가 없다.
하지만 서버 렌더링을 하면 자바스크립트가 로드되기 전에는 버튼을 클릭하거나 상호작용할 수 있는 부분은 사용하지 못하지만 자바스크립트가 로드되는 과정에서도 정적인 파일들을 화면에 보여줄 수가 있다.
그래서 네트워크가 느린 컴퓨터도 빠르게 화면을 볼 수 있다.

오늘날 서버 렌더링의 단점은 ?

  • 어떠한 것을 가져오기 위해서 모든 것을 Fetch 해줘야 한다.

  • Hydrate 을 하기 전에 모든 것을 로드해야 한다.

  • 어떤 것과도 상호 작용하기 전에 모든 것을 Hydrate 해야 한다.

❇️결국 All or Nothing !!!

이러한 방법을 해결하기 위해서 React 18에서 하는 것은 ?
1. Streaming HTML (Server)
2. Selective Hydration (Client)

Streaming HTML (서버 부분)

모든 데이터를 가져오기 전에 HTML 스트리밍하는 방법
renderToString 대신에 renderToPipeableStream 메소드를 사용

<Suspense>로 <Comments>를 감싸면 React가 페이지의 나머지 부분에 대해 HTML 스트리밍을 시작할 때까지 기다릴 필요가 없다고 React에 알린다. 대신 React는 주석 대신 자리 표시자(스피너)를 보낸다.

이후에 댓글 데이터가 서버에서 준비되면 React는 추가 HTML을 동일한 스트림에 보내고 해당 HTML을 "올바른 위치"에 넣기 위한 최소한의 인라인 <script> 태그를 보낸다.
결과적으로 React 자체가 클라이언트에 로드되기 전에도 뒤늦은 댓글 HTML이 "팝업"된다.

이것은 우리의 첫 번째 문제를 해결한다. 이제 아무것도 표시하기 전에 모든 데이터를 가져올 필요가 없다. 화면의 일부가 초기 HTML을 지연시키는 경우 모든 HTML을 지연하거나 HTML에서 제외할지 선택할 필요가 없다.
나중에 HTML 스트림에서 해당 부분이 "Pop in"되도록 허용할 수 있다.
기존 HTML 스트리밍과 달리 하향식(top-down) 순서로 발생할 필요가 없다.


Selective Hydration (클라이언트 부분)

모든 코드가 로드되기 전에 Hydrate 하는 방법

현재는 초기 HTML을 더 일찍 보낼 수 있지만 여전히 문제가 있다.
댓글 위젯에대한 JavaScript 코드가 로드될 때까지 클라이언트에서 앱을 Hydrate 을 시작할 수 없다. 코드 크기가 크면 시간이 걸릴 수 있다.
큰 번들을 피하기 위해 일반적으로 "코드 분할"을 사용한다.
코드 조각을 동기적으로 로드할 필요가 없도록 지정하면번 번들러가 이를 별도의 <script> 태그로 분할한다.

React.lazy로 코드 분할을 사용하여 기본 번들에서 댓글 코드를 분할할 수 있다.


이전에는 이 방법은 서버 렌더링에서 작동하지 않았다.

React.lazy
클라이언트 사이드 렌더링 단계에서 큰 번들의 자바스크립트 코드들을 작은 청크들 로 나누어 로드될 수 있게 해주는 역할 (리액트 18부터는 서버 사이드에서도 가능)

서버 렌더링에서 순차적으로 Hydrating 하는 순서
HTML이 순차적으로 스트리밍되고 렌더링하는 비용이 큰 컴포넌트들은 <Suspense>로 감쌈으로 인해 해당 부분이 여전히 폴백 엘리먼트를 내보내고 있어도 그와 상관없이 페이지의 다른 부분을 Hydrating을 진행한다.


나머지 부분 까지 HTML 스트리밍 된 후 JS 번들이 로드된 컴포넌트 들은 그 부분 또한 Hydrating 해준다.

사용자의 인터렉션에 따라 어떤 것을 먼저 hydration시킬지에 대한 우선순위를 정할 수있게 되었다. React는 클릭이 발생했음을 기록하고 대신 더 긴급하기 때문에 댓글에 우선 순위를 부여한다.


Transition

참조1
참조2

React 18에서는 업데이트 중에도 앱의 응답성을 유지하는 데 도움이 되는 새로운 API를 도입한다. 이 새로운 API를 사용하면 특정 업데이트를 "Transition"으로 표시하여 사용자 상호 작용을 크게 개선할 수 있다. React를 사용하면 상태 전환 중에 시각적 피드백을 제공하고 전환이 발생하는 동안 브라우저의 응답성을 유지할 수 있다.
이 기능은 리액트에서 어떠한 업데이트가 Urgent 하며 어떠한게 그러하지 않은지 알려준다.
그래서 상태 업데이트를 하는데 우선순위를 주게 된다.

대표적으로 검색 기능을 구현할 때 검색하는 Input 은 이벤트에 따라서 리렌더링이 해당화면에 업데이트 되어야 한다. 하지만 그 아래 검색 결과도 이에 따라 업데이트가 되는데 검색 결과 리스트가 많지 않더라도 내부적으로 검색 결과를 가져오는데 많은 작업을 진행할 수 있기에 검색창에 타이핑을 하는것에 따라 바로 바로 검색 결과도 업데이트를 하면 성능에 문제가 생길
수 있다.
그러하기에 이 부분은 검색 창과 결과 창 두 부분으로 나눌 수 있으며, 유저가 타이핑하는 것에 따라 즉각 반영되기를 기대하는 검색창, 그리고 검색 창보다는 UI 업데이트가 느린 것에 자연 스럽게 받아들여져야 하는 결과 창으로 나눌수 있다.


어떻게 이러한 문제점을 개선?

새로운 startTransition API는 업데이트를 "Transition"으로 표시할 수 있는 기능을 제공하여 이 문제를 해결한다.
이 API로 리액트에게 상태 업데이트하는데 우선 순위를 정해주는 것이다.

startTransition에 래핑된 업데이트는 긴급하지 않은 것으로 처리되며 클릭이나 키 누름과 같은 더 긴급한 업데이트가 들어오는 경우 중단된다. 전환이 사용자에 의해 중단되면(예: 여러 문자를 연속으로 입력) React는 다음을 throw한다. 완료되지 않은 오래된 렌더링 작업을 제거하고 최신 업데이트만 렌더링한다.
Transition을 사용하면 UI가 크게 변경되더라도 대부분의 상호 작용을 빠르게 유지할 수 있다. 또한 더 이상 관련이 없는 콘텐츠를 렌더링하는 데 시간을 낭비하지 않아도 된다.

Transition이 보류 중인 동안 어떻게?

검색 창에 타이핑을 했을 때 startTransition API로 인해 결과 창에는 UI 업데이트 우선순위가 밀려서 업데이트 보류가 일어날 때는 아래와 같이 isPending이 true로 되기에 isPending이 true일 시에 Spinner 같은 컴포넌트를 보여주면 된다.

*리액트 18 이전에는 어떻게 이러한 문제를 처리?

startTransition이 없을 때는

1. State를 두 개로 나눠서 따로 처리를 해주거나
-state가 두 개니 업데이트 처리 방법을 다르게 해 줌

2. debounce를 이용해서 처리하거나

3. setTimeout을 이용해서 처리했다.
-debounce 를 이용하거나 setTimeout 을 이용하는 것은 결국 모든 이벤트가 Schedule 되어 있고 뒤로 밀리는 것이기 때문에 이벤트가 끝나도 계속 결과를 표출하게 된다.


React Version 18로 업그레이드 하기

*리액트 버전 18로 업그레이드 하는 방법

  1. react와 react-dom을 npm 으로 부터 설치하기
    -npm install react react-dom
  2. ReactDOM.render ====> ReactDOM.createRoot 변경하기

0개의 댓글