개발자

NextJs 확장 fetch로 서버 컴포넌트에서 동적으로 api를 받는 방법

2024년 08월 09일조회 233

안녕하세요. 선배 개발자 선생님들. 오늘도 한 단계 성장하기 위해 질문을 남겨봅니다. 저는 NextJs, App router 방식으로 코드를 구현중이며, 서버 상태는 React-Query로 상태값을 관리하고 있었습니다. 왜 리액트 쿼리를 사용했는가? why? 1. Optimistic update, 무한스크롤에 대해 공부하고 적용해보고 싶었습니다. 2. 클라이언트 상태, 서버 상태를 나눈다는 개념이 너무 좋아서 서버 상태는 React-Query로 다뤘습니다. 3. statleTime, gcTime을 조정하여 캐싱기능이 좋았습니다. 갑자기 문득 나는 NextJS를 잘 쓰고 있는건가? 리액트랑 폴더 구조 말고는 다른게 없는거 아닌가? 라는 생각이 들었고, NextJs의 기능을 최대한 활용하고 나머지 불편한 부분이 생긴다면 외부 라이브러리를 사용하자! 라는 생각이 들었습니다. 그래서 저는 React-Query로 상태를 관리하던걸 NextJs의 확장 fetch로 바꿀려고 합니다. Optimistic update, 무한스크롤 기능을 제외하고 나머지 모든 서버 상태는 확장 fetch로 바꿀려고 합니다. 페이지네이션 페이지네이션 처럼 사용자와 상호 작용하는 부분, 즉 동적으로 데이터를 받아오게 하기 위해 url을 변경한 뒤, [id]/page.tsx에서 param로 받던지 혹은 header()를 통해 params를 받아서 처리를 할 수 있다고 생각하고, 저는 header()로 params를 받아서 처리를 했습니다. 모달에서의 페이지네이션 그런데 문제는 모달을 띄우고, 모달 내부에서 페이지네이션이 있는 경우 어떻게 데이터를 동적으로 받아오는지 고민을 해봐도 방법이 없는 것 같습니다. 1. 모달에서 다음 페이지 클릭시 url을 변경한다. -> 안해봤지만 동작을 할 수 있더라도 뭔가 느낌적으로 아닌 것 같습니다. 2. 클라이언트 컴포넌트에서 상태값을 서버 컴포넌트로 전달한다 -> 불가능 궁금한 점 1. 모달 내부에서 페이지네이션을 처리할때 url을 변경해서 서버 컴포넌트에서 확장 fetch로 데이터를 관리하는 게 적절할까요? 2. 모달 내부에서는 페이지네이션을 처리할 때는 react-query로 데이터를 관리하는 걸 확장 fetch로 바꿀 수 없는 건가요?? 바꿀 필요가 없는 건가요? 3. 더 좋은 방법이 있는 건가요?

이 질문이 도움이 되었나요?
'추천해요' 버튼을 누르면 좋은 질문이 더 많은 사람에게 노출될 수 있어요. '보충이 필요해요' 버튼을 누르면 질문자에게 질문 내용 보충을 요청하는 알림이 가요.

답변 2

포크코딩님의 프로필 사진

1. 방법은 자유입니다. 뭐가 정답이고 틀리고는 없습니다. 뭔가 서버컴포넌트로만 하고 싶어 하시는듯 합니다. 제 추측이 맞다면 Next의 Link 컴포넌트로 페이지 클릭시 정보를 넘기세요. 그 후 서버 페이지에 자동으로 넘어오는 searchParam을 사용 하세요. 2. 본인 마음입니다. 상관 없습니다. 3. server action을 쓰셔도 원하는 동작을 처리할 수 있습니다.

이상래님의 프로필 사진

안녕하세요. 약간 개념적으로 이해가 필요할 것 같아 답변 전달드립니다. 모달 내부에서 페이지네이션을 처리하는 가장 일반적인 방법은 클라이언트 컴포넌트에서 상태를 관리하는 것입니다. Next.js에서 제공하는 서버 컴포넌트는 서버에서 데이터를 가져와 정적으로 페이지에 렌더링할 때 매우 유용하지만, 동적인 사용자 상호작용이 필요한 경우 클라이언트 측에서 상태를 관리하는 것이 더 적합합니다. React Query와 같은 상태 관리 라이브러리에서 React Query를 사용하여 서버 데이터를 비동기적으로 가져오고, 캐싱 및 상태 관리를 수행할 수 있습니다. 서버 컴포넌트와 클라이언트 컴포넌트의 적절한 조합에서 초기 데이터를 가져오고, 클라이언트 컴포넌트에서 그 데이터를 기반으로 동적인 UI를 처리하는 방식이 좋은 균형이 될 수 있습니다. 결론적으로, 모달 내부의 페이지네이션과 같은 동적인 인터페이스에서는 클라이언트 측에서 상태를 관리하는 것이 더 적합하며, 서버 컴포넌트를 통해 초기 데이터를 가져오는 구조를 사용하는 것이 좋습니다. React Query와 같은 도구를 사용하여 서버 상태를 관리하는 것이 적절할 것으로 보입니다. 아래의 코드를 보면서 이해 하시길 바랍니다. 감사합니다. 화이팅.😎😎 예시) 1. 서버 컴포넌트에서 초기 데이터 가져오기 // app/posts/page.tsx import { Suspense } from 'react'; import PostsList from './PostsList'; export default function PostsPage() { return ( <div> <h1>Posts</h1> <Suspense fallback={<div>Loading...</div>}> <PostsList /> </Suspense> </div> ); } 2. 클라이언트 컴포넌트에서 React Query로 데이터 패칭 및 모달 구현 // app/posts/PostsList.tsx 'use client'; import { useQuery } from 'react-query'; import { useState } from 'react'; import Modal from './Modal'; async function fetchPosts(page: number) { const response = await fetch(`/api/posts?page=${page}`); return response.json(); } export default function PostsList() { const [page, setPage] = useState(1); const { data, isLoading, error } = useQuery(['posts', page], () => fetchPosts(page)); if (isLoading) return <div>Loading...</div>; if (error) return <div>Error loading posts</div>; return ( <div> <ul> {data.posts.map((post: any) => ( <li key={post.id}>{post.title}</li> ))} </ul> <button onClick={() => setPage((prev) => prev + 1)}>Next Page</button> {/* 모달을 열 수 있는 버튼 */} <button onClick={() => setModalOpen(true)}>Open Modal</button> {/* 모달 내부에서 페이지네이션 처리 */} <Modal isOpen={modalOpen} onClose={() => setModalOpen(false)}> <ul> {data.posts.map((post: any) => ( <li key={post.id}>{post.title}</li> ))} </ul> <button onClick={() => setPage((prev) => prev + 1)}>Next Page in Modal</button> </Modal> </div> ); } 3. 모달 컴포넌트 구현 // app/posts/Modal.tsx import React from 'react'; interface ModalProps { isOpen: boolean; onClose: () => void; children: React.ReactNode; } export default function Modal({ isOpen, onClose, children }: ModalProps) { if (!isOpen) return null; return ( <div className="modal"> <div className="modal-content"> <button onClick={onClose}>Close</button> {children} </div> </div> ); } 4. API 라우트 예시 // pages/api/posts.ts export default function handler(req, res) { const { page } = req.query; const postsPerPage = 10; const allPosts = [ /* 데이터 배열 */ ]; // 실제로는 데이터베이스나 외부 API에서 가져온 데이터일 것임 const start = (page - 1) * postsPerPage; const end = start + postsPerPage; const posts = allPosts.slice(start, end); res.status(200).json({ posts }); }

지금 가입하면 모든 질문의 답변을 볼 수 있어요!

현직자들의 명쾌한 답변을 얻을 수 있어요.

또는

이미 회원이신가요?

목록으로
키워드로 질문 모아보기

실무, 커리어 고민이 있다면

새로운 질문 올리기

지금 가입하면 모든 질문의 답변을 볼 수 있어요!