본문 바로가기

프론트엔드

리액트 쿼리와 리액트 라우터

리액트쿼리, 리액트 라우터 함께 사용하여 데이터 가져오기

import { useLoaderData } from 'react-router-dom';

function HomePage () {
      const navigate = useNavigation();
      const params = useParams();
      //const data = useLoaderData(); 
      // ⭐️ 위 loader() 함수에서 반환된 값을 사용하지 않고 useQuery를 계속 사용한다.
      // fetchQuery를 사용하면 react-query가 해당 요청을 보내고 응답 데이터를 캐시에 저장하게 되므로, useQuery에서는 캐시된 데이터를 사용하게 된다.
      // 다른 화면으로 나갔다가 다시 들어오게될 경우 내부적으로 가져오기를 트리거하여 업데이트된 데이터를 볼 수 있다.
      const { data, isError, error } = useQuery({
        queryKey:['events', params.id],
          queryFn: ({signal}) => fetchEvent({ signal, id: params.id }),
          staleTime: 10000 // ⭐️ loader함수와 중복요청 방지
    })
    return <EventList events={data} />
}

export default HomePage;

export function loader({params}) {
    return queryClient.fetchQuery({ // ⭐️ = useQuery
        queryKey:['events', params.id],
          queryFn: ({signal}) => fetchEvent({ signal, id: params.id }),
    });
}

리액트쿼리, 리액트 라우터 함께 사용하여 데이터 전송

import { useLoaderData } from 'react-router-dom';

function HomePage () {
      const navigate = useNavigation();
      const { state } = useNavigation();
      const params = useParams();
      const submit = useSubmit();
      //const data = useLoaderData(); 
      // ⭐️ 위 loader() 함수에서 반환된 값을 사용하지 않고 useQuery를 계속 사용한다.
      // fetchQuery를 사용하면 react-query가 해당 요청을 보내고 응답 데이터를 캐시에 저장하게 되므로, useQuery에서는 캐시된 데이터를 사용하게 된다.
      // 다른 화면으로 나갔다가 다시 들어오게될 경우 내부적으로 가져오기를 트리거하여 업데이트된 데이터를 볼 수 있다.
      const { data, isError, error } = useQuery({
        queryKey:['events', params.id],
          queryFn: ({signal}) => fetchEvent({ signal, id: params.id }),
    })

    // const { mutate, isPending } = useMutation({
      // 액션에서 모든 쿼리를 무효화함에 따라 낙관적 업데이트가 불간으
        // mutationFn: updateEvent,
          // onMutate: 
          // onError:
          // onSettled: 
    // })

    function handleSubmit(formData) {
        submit(formData, { method: 'PUT' }); // ⭐️ action 함수 트리거
    }
      let content
      if (data) {
        content = (
            <EventForm inputData={data} onSubmit={handleSubmit}>
                { 
                      state === 'submitting' ? <p>sending data...</p>
                      : <>
                          <Link to ="../">Cancel</Link>
                          <button type="submit">Update</button>
                        </>
                }
            </EventForm>
        )
    }

    return <Modal onClose={handleClose}>{content}</Modal>
}

export default HomePage;

export function loader({params}) {
    return queryClient.fetchQuery({ // ⭐️ = useQuery
        queryKey:['events', params.id],
          queryFn: ({signal}) => fetchEvent({ signal, id: params.id }),
    });
}

export async function action({request, params}) {
      const formData = await request.formData();
    const updatedData = Object.formEntries(formData); // js의 object로 변환
      await updateEvent({id: parmas.id, event: updatedData})
    await queryClient.invalidateQueries(['events']) // ⭐️ 모든 쿼리를 무효화함으로써 업데이트된 데이터를 다시 가져옴, 낙관적 업데이트 실행 안함
      return redirect('../');
}
  • api.js
    export async function updateEvent({ id, event }) {
      const response = await fetch(`http://~~/${id}`, {
          method: 'PUT',
            body: JSON.stringify({ event }),
            headers: {
              'Content-Type': 'application/json',
          }
      })
    };