Study/Memo

[React] useOptimistic hook

manon_e 2024. 11. 18. 14:35
반응형

 

useOptimistic (state, updateFn)

: 사용자가 폼을 제출할 때(네트워크 요청과 같은 백그라운드 작업이 완료되기 전),

  서버의 응답을 기다리는 대신 UI를 기대하는 결과로 즉시 업데이트하여 유저에게 보여주고 싶을 때 사용한다.

 

 

  const [optimisticState, addOptimistic] = useOptimistic(state, updateFn);

 

 

useOptimistic은 비동기 작업이 진행 중일 때 다른 상태를 보여줄 수 있게 해주는 React hook입니다.

현재 상태와 작업의 입력을 취하는 함수를 제공하고, 작업이 대기 중일 때 사용할 상태를 반환합니다.

 

이 상태는 “낙관적” 상태라고 불리는데, 실제로 작업을 완료하는 데 시간이 걸리더라도

사용자에게 즉시 작업의 결과를 표시하기 위해 일반적으로 사용됩니다.

 

import { useOptimistic } from 'react';

function AppContainer() {
  const [optimisticState, addOptimistic] = useOptimistic(
    state,
    // updateFn
    (currentState, optimisticValue) => {
      // merge and return new state
      // with optimistic value
    }
  );
}

매개변수

  • state: 작업이 대기 중이지 않을 때 초기에 반환될 값입니다.
  • updateFn(currentState, optimisticValue): 현재 상태와 addOptimistic에 전달된 낙관적인 값을 취하는 함수로, 결과적인 낙관적인 상태를 반환합니다. 순수 함수여야 합니다. updateFn은 두 개의 매개변수를 취합니다. currentState와 optimisticValue. 반환 값은 currentState와 optimisticValue의 병합된 값입니다.

반환값

  • optimisticState: 결과적인 낙관적인 상태입니다. 작업이 대기 중이지 않을 때는 state와 동일하며, 그렇지 않은 경우 updateFn에서 반환된 값과 동일합니다.
  • addOptimistic: addOptimistic는 낙관적인 업데이트가 있을 때 호출하는 dispatch 함수입니다. 어떠한 타입의 optimisticValue라는 하나의 인자를 취하며, state와 optimisticValue로 updateFn을 호출합니다.

 

 

사용예시

'use client'

import { dislikePost, likePost } from '@/app/posts/[id]/actions'
import { useOptimistic } from 'react'

const Button = ({ isLiked, likeCount, postId }: IProps) => {
  const [state, reducerFn] = useOptimistic(
    // state
    { isLiked, likeCount },

    // reducer function
    (prev, payload) => ({
      // db 응답오기전에 보여줄 UI 정보
      isLiked: !prev.isLiked,
      likeCount: prev.isLiked ? prev.likeCount - 1 : prev.likeCount + 1,
    }),
  )

  const onClick = async () => {
    // reducerFn을 먼저 작동시켜서 서버 응답 오기전에 지정한 UI를 먼저 보여줌
    reducerFn(undefined)

    if (isLiked) {
      await dislikePost(postId)
    } else {
      await likePost(postId)
    }
  }

  return (
      <button onClick={onClick} >
        {state.isLiked ? (
          <span> {state.likeCount}</span>
        ) : (
          <span>공감하기 ({state.likeCount})</span>
        )}
      </button>
  )
}

export default Button
반응형