본문 바로가기

카테고리 없음

useTransition : fallback 컴포넌트 보여주는 시간 조절

반응형

주의 : 해당 내용은 실제로 적용 불가능한 내용임. 문제를 어떤 방식으로 해결하는지에만 집중하자.

Disable timeoutMs argument by acdlite · Pull Request #19703 · facebook/react (github.com)

 

너무 빨라서 로딩 상태가 안보이는것도 일관성이 없어 좋지 않은 사용자 경험을 줄 수 있음.

이것을 "flash of loading content" 라 함

 

해당 문제를 개선해보자

아래와 같이 설정 객체를 만든다.

const SUSPENSE_CONFIG = {
  timeoutMs: 4000, // 4초 이상 걸리면 pending state표시
  busyDelayMs: 300, // css전환을 위해 최소 시간 예약해둠
  busyMinDurationMs: 700, // css전환 포함 대기시간.
}

isPending을 className 변경에 사용한다. (transition 효과가 적용되어 있음.)

현재는 busyDelayMs는 300인데, transition이 0.4로 설정되어 있다.

따라서 0.4 전환 후 minDuration 700까지 300초를 기다린 후 데이터가 있으면 데이터를 보여준다.

데이터가 없으면 4초 기다렸다가 fallback 컴포넌트를 보여준다.

function App() {
  const [pokemonName, setPokemonName] = React.useState('')
  const [startTransition, isPending] = React.useTransition(SUSPENSE_CONFIG)
  const [pokemonResource, setPokemonResource] = React.useState(null)

  React.useEffect(() => {
    if (!pokemonName) {
      setPokemonResource(null)
      return
    }
    startTransition(() => {
      setPokemonResource(createPokemonResource(pokemonName))
    })
  }, [pokemonName, startTransition])

  function handleSubmit(newPokemonName) {
    setPokemonName(newPokemonName)
  }

  function handleReset() {
    setPokemonName('')
  }

  return (
    <div className="pokemon-info-app">
      <PokemonForm pokemonName={pokemonName} onSubmit={handleSubmit} />
      <hr />
      <div className={`pokemon-info ${isPending ? 'pokemon-loading' : ''}`}>
        {pokemonResource ? (
          <PokemonErrorBoundary
            onReset={handleReset}
            resetKeys={[pokemonResource]}
          >
            <React.Suspense
              fallback={<PokemonInfoFallback name={pokemonName} />}
            >
              <PokemonInfo pokemonResource={pokemonResource} />
            </React.Suspense>
          </PokemonErrorBoundary>
        ) : (
          'Submit a pokemon'
        )}
      </div>
    </div>
  )
}
반응형