본문 바로가기
SPA/React

[React] react-query v5 변경점 알아보기 (4) - useInfiniteQuery 기능 변경

by J4J 2023. 12. 10.
300x250
반응형

안녕하세요. J4J입니다.

 

이번 포스팅은 react-query v5 변경점 알아보기 네 번째인 useInfiniteQuery 기능 변경에 대해 적어보는 시간을 가져보려고 합니다.

 

 

 

이전 글

 

[React] react-query v5 변경점 알아보기 (1) - 공통 기능 변경

[React] react-query v5 변경점 알아보기 (2) - query 공통 기능 변경

[React] react-query v5 변경점 알아보기 (3) - useQueries 기능 변경

 

 

반응형

 

 

initialPageParam 설정 방법 변경

 

useInfiniteQuery를 사용하게 되면 처음 보여주고 싶은 페이지에 대한 값을 초기화하여 원하는 페이지를 화면에 보여줄 수 있게 설정이 가능합니다.

 

5버전 이전에는 해당 설정을 다음과 같이 query function의 파라미터 중 pageParam에 적용해 줄 수 있습니다.

 

// prev react-query-v5
import { useInfiniteQuery } from '@tanstack/react-query';
import axios from 'axios';

export default function InitialPageParam() {
    const res = useInfiniteQuery<string[]>({
        queryKey: ['strings'],
        // pageParam can set initial data in queryFn parameter
        queryFn: async ({ pageParam = 1 }) =>
            (
                await axios.get('http://localhost:8080/strings/pages', {
                    params: {
                        page: pageParam,
                        limit: 2,
                    },
                })
            ).data,
        getNextPageParam: (_lastPage, allPages) => allPages.length + 1,
    });

    return (
        <main>
            <div>
                <h2>Strings</h2>
                {res.data?.pages.map((strings, page) =>
                    strings.map((string) => <p key={`${page}${string}`}>{string}</p>),
                )}
            </div>
        </main>
    );
}

 

 

 

5버전 이후부터는 위와 같이 설정하는 방법은 이제 할 수 없습니다.

 

대신 조금 더 직관적으로 설정할 수 있도록 options의 한 속성 값인 initialPageParam이 새롭게 추가되었고 해당 설정을 활용하여 동일하게 다음과 같이 적용해 볼 수 있습니다.

 

// react-query-v5
import { useInfiniteQuery } from '@tanstack/react-query';
import axios from 'axios';

export default function InitialPageParam() {
    const res = useInfiniteQuery<string[]>({
        queryKey: ['strings'],
        // pageParam cannot set initial data in queryFn parameter
        queryFn: async ({ pageParam }) =>
            (
                await axios.get('http://localhost:8080/strings/pages', {
                    params: {
                        page: pageParam,
                        limit: 2,
                    },
                })
            ).data,
        getNextPageParam: (_lastPage, allPages) => allPages.length + 1,

        // pageParam can set initial data at initialPageParam
        initialPageParam: 1,
    });

    return (
        <main>
            <div>
                <h2>Strings</h2>
                {res.data?.pages.map((strings, page) =>
                    strings.map((string) => <p key={`${page}${string}`}>{string}</p>),
                )}
            </div>
        </main>
    );
}

 

 

 

 

getNextPageParam 필수 설정

 

getNextPageParam은 nextPage에 대한 fetching이 발생되었을 때 변경될 pageParam 값을 정의하는 곳입니다.

 

해당 값은 5버전 이전에서는 필수 설정이 아니었기에 설정하지 않더라도 코드 상의 에러는 발생하지 않지만 nextPage에 대한 fetching이 발생되더라도 다음 페이지에 대한 정보는 가져오지 못합니다.

 

// prev react-query-v5
import { useInfiniteQuery } from '@tanstack/react-query';
import axios from 'axios';

export default function NeedGetNextPageParam() {
    const res = useInfiniteQuery<string[]>({
        queryKey: ['strings'],
        queryFn: async ({ pageParam = 1 }) =>
            (
                await axios.get('http://localhost:8080/strings/pages', {
                    params: {
                        page: pageParam,
                        limit: 2,
                    },
                })
            ).data,
        // getNextPageParam always not required.
    });

    return (
        <main>
            <div>
                <h2>Strings</h2>
                {res.data?.pages.map((strings, page) =>
                    strings.map((string) => <p key={`${page}${string}`}>{string}</p>),
                )}
            </div>
        </main>
    );
}

 

 

 

하지만 5버전 이후부터는 getNextPageParam을 설정하는 것이 필수로 변경되었습니다.

 

필수로 변경된 이유로는 위에서 언급한 initialPageParam 설정 방법이 변경된 것의 영향을 받았기 때문입니다.

 

그래서 이제는 다음과 같이 항상 설정을 하지 않으면 에러가 발생이 됩니다.

 

// react-query-v5
import { useInfiniteQuery } from '@tanstack/react-query';
import axios from 'axios';

export default function NeedGetNextPageParam() {
    const res = useInfiniteQuery<string[]>({
        queryKey: ['strings'],
        queryFn: async ({ pageParam }) =>
            (
                await axios.get('http://localhost:8080/strings/pages', {
                    params: {
                        page: pageParam,
                        limit: 2,
                    },
                })
            ).data,
        initialPageParam: 1,

        // if not config getNextPageParam, occur error !
        getNextPageParam: (_lastPage, allPages) => allPages.length + 1,
    });

    return (
        <main>
            <div>
                <h2>Strings</h2>
                {res.data?.pages.map((strings, page) =>
                    strings.map((string) => <p key={`${page}${string}`}>{string}</p>),
                )}
            </div>
        </main>
    );
}

 

 

 

 

maxPages 추가

 

5버전 이후에 새롭게 나온 설정인 maxPages는 총 2가지 관점에서 확인해야 합니다.

 

 

 

첫 번째는 새로운 기능 측면입니다.

 

maxPages가 제공해 주는 기본적인 기능은 5버전 이전에는 제공하지 않던 기능입니다.

 

maxPages를 설정하게 되면 제공해주는 기능으로는 maxPages에 설정한 page 개수만큼만 query key에 적재되어 캐싱되도록 도와줍니다.

 

예를 들어 nextPage에 대한 fetching이 계속 발생되어 1번 페이지부터 5번 페이지까지 데이터 호출이 발생되었고 maxPages를 3으로 설정했다면 가장 최근에 호출된 3개 페이지인 3, 4, 5번 페이지만 query에 저장되어 있도록 도와줍니다.

 

기존에는 지속적으로 query가 호출될 때마다 메모리 상에 보관하고 있어야 하는 데이터가 많아 메모리에 부담이 갈 수 있었지만 해당 기능을 활용한다면 보관하는 데이터 양이 줄어들기 때문에 효율적인 방향으로 기능 개선을 할 수 있습니다.

 

maxPages 사용 전

 

maxPages 사용 후

 

 

 

 

두 번째는 기능 변경 측면입니다.

 

5버전 이전에는 refetchPage라는 함수를 활용하여 특정 페이지들에 대해서만 refetch가 발생되도록 적용해 볼 수 있습니다.

 

하지만 5버전 이후부터는 refetchPage가 삭제되었습니다.

 

대신 maxPages가 추가되었기 때문에 maxPages의 기능과 기존에 존재하던 queryClient.refetchQueries를 활용하여 유사한 기능들을 적용해 볼 수는 있습니다.

 

최종적으로 5버전 이전에는 다음과 같이 코드를 사용해 볼 수 있었습니다.

 

// prev react-query-v5
import { useInfiniteQuery } from '@tanstack/react-query';
import axios from 'axios';

export default function MaxPages() {
    const res = useInfiniteQuery<string[]>({
        queryKey: ['strings'],
        queryFn: async ({ pageParam = 1 }) =>
            (
                await axios.get('http://localhost:8080/strings/pages', {
                    params: {
                        page: pageParam,
                        limit: 2,
                    },
                })
            ).data,
        getNextPageParam: (_lastPage, allPages) => allPages.length + 1,
        // all page datas caching
    });

    return (
        <main>
            <div>
                <h2>Strings</h2>
                {res.data?.pages.map((strings, page) =>
                    strings.map((string) => <p key={`${page}${string}`}>{string}</p>),
                )}
            </div>

            <button onClick={() => res.fetchNextPage()}>nextPage</button>

            {/* do fetch only selected pages */}
            <button
                onClick={() =>
                    res.refetch({
                        refetchPage: (_lastPage, index, allPages) => {
                            return index >= allPages.length - 3;
                        },
                    })
                }
            >
                최근 3개 페이지만 refetch 수행
            </button>
        </main>
    );
}

 

 

 

하지만 5버전 이후부터는 다음과 같이 사용해 볼 수 있게 변경되었습니다.

 

// react-query-v5
import { useInfiniteQuery, useQueryClient } from '@tanstack/react-query';
import axios from 'axios';

export default function MaxPages() {
    const queryClient = useQueryClient();
    const res = useInfiniteQuery<string[]>({
        queryKey: ['strings'],
        queryFn: async ({ pageParam }) => {
            return (
                await axios.get('http://localhost:8080/strings/pages', {
                    params: {
                        page: pageParam,
                        limit: 2,
                    },
                })
            ).data;
        },
        initialPageParam: 1,
        getNextPageParam: (_lastPage, allPages) => allPages.length + 1,

        // only last 3 page datas caching
        maxPages: 3,
    });

    return (
        <main>
            <div>
                <h2>Strings</h2>
                {res.data?.pages.map((strings, page) =>
                    strings.map((string) => <p key={`${page}${string}`}>{string}</p>),
                )}
            </div>

            <button onClick={() => res.fetchNextPage()}>nextPage</button>

            {/* do not fetch only selected pages */}
            <button
                onClick={() =>
                    queryClient.refetchQueries({
                        queryKey: ['strings'],
                    })
                }
            >
                최근 3개 페이지만 (= 모든 페이지) refetch 수행
            </button>
        </main>
    );
}

 

 

 

 

usePrefetchInfinteQuery pages 추가

 

5버전 이전에서는 prefetchInfiniteQuery를 활용하여 query에 대한 결과를 prefetching을 수행할 때 초기 페이지로 설정한 값에 대해서만 prefetching이 발생되었습니다.

 

하지만 5버전 이후부터는 prefetchInfiniteQuery options에 pages라는 속성이 추가되었고 pages를 설정하게 되면 더 많은 페이지들을 prefetching 할 수 있게 되었습니다.

 

 

 

그래서 5버전 이전에는 다음과 같이 사용하여 초기 페이지만 prefetching 할 수 있었습니다.

 

// prev react-query-v5
import { useInfiniteQuery, useQueryClient } from '@tanstack/react-query';
import axios from 'axios';

function Page() {
    const res = useInfiniteQuery<string[]>({
        queryKey: ['strings'],
        queryFn: async ({ pageParam = 1 }) =>
            (
                await axios.get('http://localhost:8080/strings/pages', {
                    params: {
                        page: pageParam,
                        limit: 2,
                    },
                })
            ).data,
    });

    return (
        <main>
            <div>
                <h2>Strings</h2>
                {res.data?.pages.map((strings, page) =>
                    strings.map((string) => <p key={`${page}${string}`}>{string}</p>),
                )}
            </div>
        </main>
    );
}

export default function PrefetchPages() {
    const queryClient = useQueryClient();
    queryClient.prefetchInfiniteQuery<string[]>({
        queryKey: ['strings'],
        queryFn: async ({ pageParam = 1 }) =>
            (
                await axios.get('http://localhost:8080/strings/pages', {
                    params: {
                        page: pageParam,
                        limit: 2,
                    },
                })
            ).data,
        getNextPageParam: (_lastPage, allPages) => allPages.length + 1,
        // only initial page prefetching
    });

    return <Page />;
}

 

 

 

하지만 5버전 이후부터 pages를 추가하여 더 많은 페이지들의 query 데이터가 prefetching 되는 것을 볼 수 있습니다.

 

// react-query-v5
import { useInfiniteQuery, useQueryClient } from '@tanstack/react-query';
import axios from 'axios';

function Page() {
    const res = useInfiniteQuery<string[]>({
        queryKey: ['strings'],
        queryFn: async ({ pageParam }) =>
            (
                await axios.get('http://localhost:8080/strings/pages', {
                    params: {
                        page: pageParam,
                        limit: 2,
                    },
                })
            ).data,
        getNextPageParam: (_lastPage, allPages) => allPages.length + 1,
        initialPageParam: 1,
    });

    return (
        <main>
            <div>
                <h2>Strings</h2>
                {res.data?.pages.map((strings, page) =>
                    strings.map((string) => <p key={`${page}${string}`}>{string}</p>),
                )}
            </div>
        </main>
    );
}

export default function PrefetchPages() {
    const queryClient = useQueryClient();
    queryClient.prefetchInfiniteQuery<string[]>({
        queryKey: ['strings'],
        queryFn: async ({ pageParam }) => {
            return (
                await axios.get('http://localhost:8080/strings/pages', {
                    params: {
                        page: pageParam,
                        limit: 2,
                    },
                })
            ).data;
        },
        initialPageParam: 1,
        getNextPageParam: (_lastPage, allPages) => allPages.length + 1,

        // 3 pages can prefetched
        pages: 3,
    });

    return <Page />;
}

 

 

 

 

 

 

 

 

이상으로 react-query v5 변경점 알아보기 네 번째인 useInfiniteQuery 기능 변경에 대해 간단하게 알아보는 시간이었습니다.

 

읽어주셔서 감사합니다.

 

 

 

728x90
반응형

댓글