"일꾼이 일을 잘하려면 먼저 도구를 갈고 닦아야 한다." - 공자, 『논어』.
첫 장 > 프로그램 작성 > React 쿼리를 사용하여 피드 페이지 구축

React 쿼리를 사용하여 피드 페이지 구축

2024-11-09에 게시됨
검색:956

Building a Feed Page Using React Query

목표

이 글에서는 React Query를 사용하여 피드 페이지를 구축하는 방법을 살펴보겠습니다!

우리가 만들 내용은 다음과 같습니다.

이 문서에서는 앱 구축과 관련된 모든 단계와 세부 사항을 다루지는 않습니다.
대신 핵심 기능, 특히 "무한 스크롤" 및 "맨 위로 스크롤" 기능에 중점을 둘 것입니다.
전체 구현에 대한 컨설팅에 관심이 있다면 이 GitHub 저장소에서 전체 코드베이스를 찾을 수 있습니다.

애플리케이션 설정

먼저 다음 명령을 사용하여 Vite를 사용하여 React 애플리케이션을 만듭니다.

npm create vite@latest feed-page-rq -- --template react-ts

그리고 필요한 종속성인 axiosreact-query:
를 설치합니다.

npm install axios @tanstack/react-query@4

RESTful 서버도 모의해야 하므로 json-server를 사용하겠습니다. 이를 통해 React 앱에 가짜 API 엔드포인트를 제공하여 백엔드를 시뮬레이션할 수 있습니다.

우리는 다음 속성을 포함하는 게시물 엔터티로 작업할 것입니다:

{
  "id": "1",
  "title": "Sample Post Title",
  "body": "This is a sample post body",
  "userId": "2",
  "createdAt": 1728334799169 // date timestamp
}

서버가 설정되면 다음을 사용하여 서버를 실행합니다.

npx json-server --watch db.json

"무한스크롤" 구현

"무한 스크롤" 기능의 메커니즘은 간단합니다.
사용자가 게시물 목록을 스크롤하고 컨테이너 하단에 접근하면 React Query는 다음 게시물 배치를 찾습니다. 더 이상 로드할 게시물이 없을 때까지 이 프로세스가 반복됩니다.

현재 스크롤 위치(scrollTop)를 표시 화면 높이(클라이언트 높이)에 추가하고 이 합계를 와 비교하여 사용자가 하단 근처에 있는지 확인합니다. 컨테이너의 총 높이(scrollHeight).
합계가 전체 컨테이너 높이보다 크거나 같으면 React Query에 다음 페이지를 가져오도록 요청합니다.

  const { scrollTop, scrollHeight, clientHeight } = elemRef.current;
  if(scrollTop   clientHeight >= scrollHeight) {
      fetchNextPage();
  }

1단계: useInfiniteQuery 구성

먼저 React Query의 useInfiniteQuery를 래핑하기 위한 사용자 정의 후크를 생성합니다.

사용자 정의 후크 내에서 초기 페이지 번호와 다음 페이지를 검색하는 함수를 지정하여 페이지별로 게시물을 가져오도록 쿼리를 구성합니다.

import { QueryFunctionContext, useInfiniteQuery } from "@tanstack/react-query";
import axios from "axios";

const URL = "http://localhost:3000";
const POSTS = "posts";

export const fetchInfinitePosts = async ({
  pageParam,
}: QueryFunctionContext) => {
  const result = await axios.get(
    `${URL}/${POSTS}?_sort=-createdAt&_page=${pageParam}&_per_page=10`,
  );
  return result.data;
};

export const useInfinitePosts = () => {
  return useInfiniteQuery({
    queryKey: [POSTS],
    queryFn: fetchInfinitePosts,
    initialPageParam: 1,
    getNextPageParam: (lastPage) => lastPage.next,
  });
};

2단계: PostList에 게시물 표시

이제 구성요소의 사용자 정의 후크를 사용하여 게시물 목록을 표시하겠습니다.
이를 위해 먼저 페이지를 반복한 다음 각 페이지 내의 게시물을 반복하여 렌더링합니다.

import { useInfinitePosts } from './hooks/useInfinitePosts';

const PostList = () => {
  const { data: postLists } = useInfinitePosts();

  return (
    
{postLists?.pages.map((page) => page.data.map(post => (

{post.title}

{post.body}

)) )}
); }; export default PostList;

3단계: 무한 스크롤 동작 구현

무한 스크롤 동작을 구현하려면 게시물이 표시되는 컨테이너에 스크롤 이벤트 리스너를 추가해야 합니다. 이 이벤트 리스너는 사용자가 컨테이너 하단 근처에 있는지 확인하고 그렇다면 fetchNextPage를 호출하여 더 많은 콘텐츠를 로드하는 onScroll 함수를 트리거합니다.

import React, { useRef, useEffect } from 'react';
import { useInfinitePosts } from './hooks/useInfinitePosts';

const PostList = () => {
  const { data: postLists, fetchNextPage } = useInfinitePosts();
  const elemRef = useRef(null);

  const onScroll = useCallback(() => {
    if (elemRef.current) {
      const { scrollTop, scrollHeight, clientHeight } = elemRef.current;
      const isNearBottom = scrollTop   clientHeight >= scrollHeight;
      if(isNearBottom) {
          fetchNextPage();
      }
    }
  }, [fetchNextPage]);

  useEffect(() => {
    const innerElement = elemRef.current;
  
    if (innerElement) {
      innerElement.addEventListener("scroll", onScroll);

      return () => {
        innerElement.removeEventListener("scroll", onScroll);
      };
    }
  }, [onScroll]);

  return (
    
{postLists?.pages.map((page, i) => page.data.map(post => (

{post.title}

{post.body}

)) )}
); }; export default PostList;

"맨 위로 스크롤" 구현

다음으로 새 게시물이 추가될 때 표시되는 '맨 위로 스크롤' 버튼을 만들어 보겠습니다. 이 버튼을 사용하면 사용자가 맨 위로 빠르게 돌아가 최신 업데이트를 볼 수 있습니다.
게시물은 생성 날짜순으로 정렬되므로 새로 추가된 게시물은 목록 상단에 표시됩니다.
우리 기능의 로직은 이 전제 위에 구축될 것입니다.

1단계: prevNewestPost에 대한 쿼리 만들기

가장 최근에 작성된 게시물을 가져오고 캐시하는 새 쿼리를 만드는 것부터 시작합니다. 이 게시물을 prevNewestPost라고 하겠습니다.
우리는 prevNewestPost가 목록의 첫 번째 게시물과 몇 단계 뒤처지거나 최대로 일치하도록 하려고 합니다. 따라서 다시 가져오기를 수동으로 제어하겠습니다.
쿼리 옵션에서 available: false를 설정하여 이를 달성합니다.

export const fetchNewestPost = async () => {
  const result = await axios.get(`${URL}/${POSTS}?_sort=-createdAt`);
  return result.data[0];
};

export const useNewestPost = () => {
  return useQuery({
    queryKey: [POSTS, "newest"],
    queryFn: () => fetchNewestPost(),
    enabled: false,
  });
};

2단계: prevNewestPost와 첫 번째 게시물 비교

React Query를 사용하면 특정 이벤트에 대해 게시물 목록이 자동으로 업데이트됩니다. (이러한 이벤트의 전체 목록에 대한 문서 링크는 다음과 같습니다.)
이 업데이트된 목록을 사용하여 prevNewestPost와 첫 번째 게시물을 비교하여 '맨 위로 스크롤' 버튼을 표시할 시기를 결정합니다.
서로 다른 경우에는 새로운 글이 추가된 것이므로 '맨 위로 스크롤' 버튼이 표시됩니다.

setIsShowButton(postLists?.pages[0].data[0].id !== prevNewestPost?.id);

3단계: 커서가 상단에 있을 때 버튼 숨기기

사용자가 게시물 목록 컨테이너 상단에 있을 때 "맨 위로 스크롤" 버튼을 표시하면 안 됩니다.
따라서 사용자가 최상위에 도달하면 쿼리 다시 가져오기를 트리거하여 prevNewestPost를 현재 최신 게시물과 다시 동기화해야 합니다.

  const { data: prevNewestPost, refetch } = useNewestPost();
  const [isShowButton, setIsShowButton] = useState(false);
  
  useEffect(() => {
    if (!isNearTop) {
      setIsShowButton(postLists?.pages[0].data[0].id !== prevNewestPost?.id);
    } else {
      setIsShowButton(false);
      refetch();
    }
  }, [postLists, prevNewestPost, isNearTop]);

4단계: 맨 위로 스크롤 버튼 만들기

ToTopBtn 버튼을 클릭하면 목록 상단으로 스크롤되어 버튼을 숨기고 데이터를 다시 가져와 prevNewestPost를 목록의 첫 번째 게시물과 동기화하는 기존 로직이 트리거됩니다.

import { RefObject } from "react";

type ToTopBtnProps = {
  elemRef: RefObject;
};

export default function ToTopBtn({ elemRef }: ToTopBtnProps) {
  return (
    
         
  ); }

5단계: 새 게시물을 추가하여 테스트

'맨 위로 스크롤' 버튼 기능을 테스트하려면 피드에 새 게시물을 추가해야 합니다.
이를 위해 React Query의 useMutation을 사용하여 서버에 새 게시물을 추가하고 각 변형 후에 캐시된 postList의 유효성을 다시 검사합니다.
사용자가 버튼을 클릭할 때마다 무작위 데이터로 새 게시물을 만들 수 있는 변형을 설정하겠습니다.

export const savePost = async (post: NewPostData) =>
  axios.post(`${URL}/${POSTS}`, post);

export const useAddPost = () => {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: savePost,
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: [POSTS] });
    },
  });
};
export default function AddNewPostBtn() {
  const mutation = useAddPost();

  return (
    
         
  );

결론

이 튜토리얼에서는 실제 사용 사례를 통해 React Query의 강력한 기능을 살펴보고 개발자가 사용자 경험을 향상시키는 동적 인터페이스를 구축하는 데 도움이 되는 기능을 강조했습니다.

릴리스 선언문 이 기사는 https://dev.to/mohamed_hammi/build-a-feed-page-using-react-query-nbi?1에서 재현됩니다.
최신 튜토리얼 더>

부인 성명: 제공된 모든 리소스는 부분적으로 인터넷에서 가져온 것입니다. 귀하의 저작권이나 기타 권리 및 이익이 침해된 경우 자세한 이유를 설명하고 저작권 또는 권리 및 이익에 대한 증거를 제공한 후 이메일([email protected])로 보내주십시오. 최대한 빨리 처리해 드리겠습니다.

Copyright© 2022 湘ICP备2022001581号-3