반응형
우리의 목적
필요한 데이터를 최대한 즉시 가져오자
보통 데이터 fetch는 useEffect를 이용하는데, 이는 dom이 실제로 화면에 그려져 interactive한 이후이다.
(코드 로드 > 코드 파싱 > 코드 실행 > 컴포넌트 렌더링 > useEffect로 요청)
그리고 사용자는 렌더링 시간 + 데이터 가져오는 시간 만큼을 시리얼하게 기다려야 한다.
화면 그리기 전에 필요한 데이터를 가져올 수는 없을까?
Render as you fetch (렌더와 데이터 페치를 동시에)를 사용한다.
해당 방법을 위해선 suspense가 필요하다.
먼저, loading, error, success를 사용하는 useEffect훅을 대체한다.
성공하면 데이터, 그 외에는 promise를 throw 한다.
function createResource(promise) {
let status = 'pending'
let result = promise.then(
resolved => {
status = 'success'
result = resolved
},
rejected => {
status = 'error'
result = rejected
},
)
return {
read() {
if (status === 'pending') throw result
if (status === 'error') throw result
if (status === 'success') return result
throw new Error('This should be impossible')
},
}
}
해당 데이터를 사용하는 view를 만든다.
function PokemonInfo({pokemonResource}) {
const pokemon = pokemonResource.read()
return (
<div>
<div className="pokemon-info__img-wrapper">
<img src={pokemon.image} alt={pokemon.name} />
</div>
<PokemonDataView pokemon={pokemon} />
</div>
)
}
서스펜스와 에러바운더리로 감싼다.
에러바운더리는 자바스크립트 오류와 비동기 오류를 잡아 케이스에 따라 뷰를 보여주는 책임,
서스펜스는 비동기 로딩 상태와 성공 시 뷰를 보여주는 책임을 담당한다.
사용자 경험을 고려하여 컴포넌트를 배치한다.
function createPokemonResource(pokemonName) {
return createResource(fetchPokemon(pokemonName))
}
function App() {
const [pokemonName, setPokemonName] = React.useState('')
const [pokemonResource, setPokemonResource] = React.useState(null)
React.useEffect(() => {
if (!pokemonName) {
setPokemonResource(null)
return
}
setPokemonResource(createPokemonResource(pokemonName))
}, [pokemonName])
function handleSubmit(newPokemonName) {
setPokemonName(newPokemonName)
}
function handleReset() {
setPokemonName('')
}
return (
<div className="pokemon-info-app">
<PokemonForm pokemonName={pokemonName} onSubmit={handleSubmit} />
<hr />
<React.Suspense
fallback={
<div className="pokemon-info">
<PokemonInfoFallback name={pokemonName} />
</div>
}
>
<div className="pokemon-info">
{pokemonResource ? (
<PokemonErrorBoundary
onReset={handleReset}
resetKeys={[pokemonName]}
>
<PokemonInfo pokemonResource={pokemonResource} />
</PokemonErrorBoundary>
) : (
'Submit a pokemon'
)}
</div>
</React.Suspense>
</div>
)
}
반응형
'FrontEnd' 카테고리의 다른 글
Suspense와 Image (0) | 2021.12.24 |
---|---|
Suspense와 리소스 캐싱하기 (0) | 2021.12.24 |
Simple Data-Fetching with React Suspense (0) | 2021.12.24 |
[짤막글][Concurrent Mode] 비동기 모드 사용 방법 (0) | 2021.12.23 |
[WIP] 리액트 공식문서 읽기 : Thinking in React with Hooks (0) | 2021.12.23 |