프리온보딩_리액트해부학_React18에서 추가된 hook

Eugenius1st·2023년 3월 30일
0
post-thumbnail

리액트 해부학 사전 과제

과제리스트

  1. React Lifecycle에 대해 간단히 설명해주세요
  2. React18에서 업데이트 된 기능에 대해 설명해주세요
  3. React18에서 추가된 hook들에 대해 설명해주세요
  4. 요즘 관심있는 주제가 있다면 알려주세요

React18에서 추가된 hook

🌿1. useId

클라이언트와 서버간의 hydrationmismatch를 피하면서 유니크 아이디를 생성할 수 있는 새로운 훅이다. 이는 주로 고유한 'id'가 필요한 접근성 API와 사용되는 컴포넌트에 유용할 것으로 기대된다. React18에서 새로운 스트리밍 렌더러가 HTML을 순서에 어긋나지 않게 전달해 줄 수 있다.

아이디는 기본적으로 트리 내부의 노드의 위치를 나타내는 base 32 문자열이다. 트리가 여러 children으로 분기될 때마다, 현재 레벨에서 자식 수준을 나타내는 비트를 시퀀스 왼쪽에 추가하게 된다.

🌿2. useTransition, startTransition

이 두 메소드를 사용하면 일부 상태 업데이트를 긴급하지 않은 것(not urgent)로 표시할 수 있다. 이 것으로 표시되지 않은 상태 업데이트는 긴급 업데이트로 간주한다. 긴급한 상태 업데이트(ex. input text 등)가 긴급하지 않은 상태 업데이트(검색 결과 목록 렌더링)을 중단시킬 수 있다.

function App() {
  const [resource, setResource] = useState(initialResource)
  const [startTransition, isPending] = useTransition({ timeoutMs: 3000 })
  return (
    <>
      <button
        disabled={isPending}
        onClick={() => {
          startTransition(() => {
            const nextUserId = getNextId(resource.userId)
            setResource(fetchProfileData(nextUserId))
          })
        }}
      >
        Next
      </button>
      {isPending ? 'Loading...' : null} <ProfilePage resource={resource} />
    </>
  )
}
  • startTransition는 함수로, 리액트에 어떤 상태변화를 지연하고 싶은지 지정할 수 있다.
  • isPending은 진행 여부로, 트랜지션이 진행중인지 알 수 있다.
  • timeoutMs로 최대 3초 간 이전 화면을 유지한다.

🌿3. useDeferredValue

useDeferredValue를 사용하면, 트리에서 급하지 않은 부분의 재렌더링을 지연할 수 있다. 이는 debounce와 비슷하지만, 몇 가지 더 장점이 있다. 고정된 지연 시간이 없으므로, 리액트는 첫 번째 렌더링이 반영되는 즉시 지연 렌더링을 시도한다. 이 지연된 렌더링은 인터럽트가 가능하며, 사용자 입력을 차단하지 않는다.

import { useDeferredValue } from 'react'

const deferredValue = useDeferredValue(value, {
  timeoutMs: 5000,
})

'value'의 값이 바뀌어도, 다른 렌더링이 발생하는 동안에는 최대 5000ms가 지연된다. 시간이 다되거나, 렌더링이 완료된다면 deferredValue가 변경되면서 상태값이 변하게 될 것이다.

🌿4. useSyncExternalStore

useSyncExternalStore는 스토어에 대한 업데이트를 강제로 동기화하여 외부 스토어가 concurrent read를 지원할 수 있도록하는 새로운 훅이다. 외부 데이터의 원본에 대한 subscript를 필요로 할 때 더 이상 useEffet를 사용하지 않고, 이는 리액트 외부 상태와 통합되는 모든 라이브러리에 권장된다.

  • External Store : 외부 스토어라는 것은 우리가 subscribe하는 무언가를 의미한다. 예를 들어 리덕스 스토어, 글로벌 변수, dom 상태 등이 될 수 있다.
  • Internal Store : 'props', 'context', 'useState', 'useReducer' 등 리액트가 관리하는 상태를 의미한다.
  • Tearing : 시각적인 비일치를 의미한다. 예를 들어, 하나의 상태에 대해 UI가 여러 상태로 보여지고 있는(=각 컴포넌트 별로 업데이트 속도가 달라서 발생하는) 상태를 말한다.

🌿5. useInsertionEffect

useInsertionEffectcss-in-js 라이브러리가 렌더링 도중에 스타일을 삽입할 때 성능 문제를 해결할 수 있는 새로운 훅이다. css-in-js 라이브러리를 사용하지 않는다면 사용할 필요가 없다. 이 훅은 DOM이 한번 mutate된 이후에 실행되지만, layout effect가 일어나기 전에 새 레이아웃을 한 번 읽는다. 이는 React 18 이전의 문제를 해결할 수 있으며, React 18에서는 나아가 concurrent 렌더링 중에 브라우저에 리액트가 값을 반환하므로, 레이아웃을 한번 더 계산할 수 있는 기회가 생겨 매우 중요하다.

어떻게 보면 useLayoutEffect와 비슷한데, 차이가 있다면 DOM 노드에 대한 참조에 엑세스 할 수 있다는 것이다.


3) 새로운 Client 및 Server Rendering API

(1) React DOM Client

react-dom/client에 새로운 API가 추가되었다.

🌿1. createRoot

렌더링 또는 언마운트할 루트를 만드는 새로운 메소드다. ReactDOM.render 대신 사용하며, React18의 새로운 기능동작을 위해 필수로 사용해야한다.

//before
import ReactDOM from 'react-dom'
import App from 'App'

const container = document.getElementById('root')

ReactDOM.render(<App name="yceffort blog" />, container)

ReactDOM.render(<App name="yceffort post" />, container)
JAVASCRIPT
 

//after
import ReactDOM from 'react-dom'
import App from 'App'

const container = document.getElementById('root')

// 루트 생성
const root = ReactDOM.createRoot(container)

// 최초 렌더링
root.render(<App name="yceffort blog" />) // During an update, there is no need to pass the container again
// 업데이트 시에는, container를 다시 넘길 필요가 없다.
root.render(<App name="yceffort post" />)

🌿2. hydrateRoot

서버사이드 렌더링 애플리케이션에서 hydrate하기 위한 새로운 메소드이다. 새로운 React DOM Server API와 함께 ReactDOM.hydrate 대신 사용하면 된다. React18의 새로운 기능동작을 위해 필수로 사용해야한다.

//before
import ReactDOM from 'react-dom'
import App from 'App'

const container = document.getElementById('root')
ReactDOM.hydrate(<App name="yceffort blog" />, container)
 

//after
import ReactDOM from 'react-dom'
import App from 'App'

const container = document.getElementById('root')
const root = ReactDOM.hydrateRoot(container, <App name="yceffort blog" />)

위 두 메소드 모드 'onRecoverableError'를 옵션으로 받을 수 있는데, 리액트가 렌더링이나 hydration시 에러가 발생하여 리커버리를 시도할 때 logging을 할 수 있는 목적으로 제공된다. 기본값으로 reportError나 구형 브라우저에서는 'console.error'를 쓴다.

(2) React DOM Server

'react-dom/server'에 새로운 API가 추가되었으며, 이는 서버에서 steaming Suspense를 완벽하게 지원한다.

🌿1. renderToPipableStream

  • node 환경에서 스트리밍 지원
  • <Suspense>와 함께 사용 가능
  • 콘텐츠가 잠시 사라지는 문제없이 lazy와 함께 코드 스플리팅 가능
  • 지연된 콘텐츠 블록이 있는 HTML 스트리밍이 나중에 뜰 수 있음

🌿2. renderToReadableStream

  • Cloudflare, deno와 같이 모던 엣지 런타임 환경에서 스트리밍 지원
  • renderToString는 여전히 존재하지만, 사용하는 것이 권장되지는 않는다.

출처: https://doqtqu.tistory.com/348#2.5.%20useInsertionEffect

profile
최강 프론트엔드 개발자가 되고싶은 안유진 입니다

0개의 댓글