MSW 와 리액트 쿼리 - 3

hojoon·2023년 8월 14일
0

리액트

목록 보기
9/10

keepPreviousData 옵션

keepPreviousData: true,
  • 새로요청이 될때까지 예전 데이터를 저장하고 새로운 데이터가 오면 업데이트한다 라는 옵션이다.
  • 컴포넌트 자체를 바꿀때 유용하게 쓸 수 있다.

infinite Queries

  • 무한스크롤 구현할 때 유용하게 쓸 수 있다.

Placeholder Query Data

  • 목록조회시 가져온 일부 데이터를 상세 조회하기 전에 미리 보여줄때..
function Todos() {
  const result = useQuery('todos', () => fetch('/todos'), {
    placeholderData: placeholderTodos,
  })
}
  • placeholderData : placeholderTodos
  • placeholderData가 있으면 쓴다.
function Todo({ blogPostId }) {
  const result = useQuery(['blogPost', blogPostId], () => fetch(`/blogPosts/${blogPostId}`), {
    placeholderData: () => {
      // Use the smaller/preview version of the blogPost from the 'blogPosts' query as the placeholder data for this blogPost query
      return queryClient
        .getQueryData('blogPosts')
        ?.find(d => d.id === blogPostId)
    },
  })
}
  • post목록에서 id와 blogPostId 와 같은것을 찾아서 placeholderdata로 쓴다.
function Todos() {
  // Show initialTodos immediately, but won't refetch until another interaction event is encountered after 1000 ms
  const result = useQuery('todos', () => fetch('/todos'), {
    initialData: initialTodos,
    staleTime: 60 * 1000 // 1 minute
    // This could be 10 seconds ago or 10 minutes ago
    initialDataUpdatedAt: initialTodosUpdatedTimestamp // eg. 1608412420052
  })
}
  • 1분동안 refetch 안한다.

Initial Query Data

차이점
observer level vs cache level

  • placeholder 는 진짜와 같지 않아도 된다.
  • initial data 는 캐시 데이터

prefetching

const prefetchTodos = async () => {
  // The results of this query will be cached like a normal query
  await queryClient.prefetchQuery('todos', fetchTodos)
}

useQuery로 호출하지 않아도 미리 준비한다.

  • cache가 이미 있고 not invalidated 하다면 fetch 하지 않음
  • staleTime이 지났다면 fetch해야 함
  • useQuery가 수행되지 않는다면 ,cacheTime 이후에 GC로 제거된다.

prefetch해놓고도 쓰이지 않는다면 가비지컬렉터에 의해 알아서 삭제된다.

Mutations

  • 서버에 있는 데이터를 바꾸는 역할! (중요할듯 잘보자)
  • create / update / delete data
  • reset / side effect

useQuery와는 상태에 대해서는 거의 비슷함, 사이드 이펙트 부분이 좀 다르다.
리액트 16버전에서는 이벤트를 직접 받아서 동작 불가능

const CreateTodo = () => {
  const mutation = useMutation(formData => {
    return fetch('/api', formData)
  })
  const onSubmit = event => {
    event.preventDefault()
    mutation.mutate(new FormData(event.target))
  }

  return <form onSubmit={onSubmit}>...</form>
}
  • 함수를 따로 빼줘야 함
 {mutation.error && (
        <h5 onClick={() => mutation.reset()}>{mutation.error}</h5>
      )}
  • 이렇게 에러가 있으면 호출하기 전 상태로 리셋시킬수도 있음

중요한 사이드 이펙트 부분!

  • 서버에 호출하면 백엔드 DB가 바뀔껀데 그 부분을 어떻게 변경할지에 대한 고민 부분!

queryClient.invalidateQueries()

// Invalidate every query in the cache
queryClient.invalidateQueries()
// Invalidate every query with a key that starts with `todos`
queryClient.invalidateQueries('todos')
  • 아무것도 안주면 모든 쿼리들을 invalidation 해버림
  • key를 주면 특정 key들만 invalidation 함
queryClient.invalidateQueries({
  predicate: query =>
    query.queryKey[0] === 'todos' && query.queryKey[1]?.version >= 10,
})

// The query below will be invalidated
const todoListQuery = useQuery(['todos', { version: 20 }], fetchTodoList)

// The query below will be invalidated
const todoListQuery = useQuery(['todos', { version: 10 }], fetchTodoList)

// However, the following query below will NOT be invalidated
const todoListQuery = useQuery(['todos', { version: 5 }], fetchTodoList)
  • 버전별로 invalidate 가능.!

Cancellation

  • 요청에 대한 결과를 반영하지 않겠다..!!!
  • 리액트 쿼리에서 제공하는 기능이라기 보다는 axios에서 제공하는 cancle을 어떻게 활용할것인가에 대한 예제.!
import axios from 'axios'

const query = useQuery('todos', ({ signal }) => {
  // Create a new CancelToken source for this request
  const CancelToken = axios.CancelToken
  const source = CancelToken.source()

  const promise = axios.get('/todos', {
    // Pass the source token to your request
    cancelToken: source.token,
  })

  // Cancel the request if React Query signals to abort
  signal?.addEventListener('abort', () => {
    source.cancel('Query was cancelled by React Query')
  })

  return promise
})
  • cancelToken 활용

그러나 v0.22.0 이상부터는 signal 옵션

import axios from 'axios'

const query = useQuery('todos', ({ signal }) =>
  axios.get('/todos', {
    // Pass the signal to `axios`
    signal,
  })
)

취소는 어떻게 함?

const [queryKey] = useState('todos')

const query = useQuery(queryKey, async ({ signal }) => {
  const resp = await fetch('/todos', { signal })
  return resp.json()
})

const queryClient = useQueryClient()

return (
  <button onClick={(e) => {
    e.preventDefault()
    queryClient.cancelQueries(queryKey)
   }}>Cancel</button>
)

Scroll Restoration도 가능

  • 캐시에 스크롤위치를 담을수 있기 때문에

Filters

// Cancel all queries
await queryClient.cancelQueries()

// Remove all inactive queries that begin with `posts` in the key
queryClient.removeQueries('posts', { inactive: true })

// Refetch all active queries
await queryClient.refetchQueries({ active: true })

// Refetch all active queries that begin with `posts` in the key
await queryClient.refetchQueries('posts', { active: true })

Mutation Filters

// Get the number of all fetching mutations

await queryClient.isMutating()

// Filter mutations by mutationKey
await queryClient.isMutating({ mutationKey: "post" })

// Filter mutations using a predicate function
await queryClient.isMutating({ predicate: (mutation) => mutation.options.variables?.id === 1 })

정리

profile
프론트? 백? 초보 개발자의 기록 공간

0개의 댓글