[Next Blog] 캐러셀 포스트 보여주기

정세영·2023년 9월 12일
0

Next.js

목록 보기
12/12

이번에는 non featured Posts를 carousel로 보여주도록 만들었다. react로 만들어본 경험은 있는데 NextJS를 사용하여 만드는 것은 처음이라 기록해보았다.

non featured posts 데이터 받아오기

비즈니스 로직

캐러셀로는 featured posts를 제외한 non featured posts를 보여줄 것이기 때문에 따로 non featured posts 데이터를 받아와야한다.

src/service/posts.ts

export const getAllPosts = cache(async () => {
  console.log("getAllPosts");

  const filePath = path.join(process.cwd(), "data", "posts.json");
  return readFile(filePath, "utf-8")
    .then<Post[]>(JSON.parse)
    .then((posts) => posts.sort((a, d) => (a.date > d.date ? -1 : 1)));
});

export async function getFeaturedPosts(): Promise<Post[]> {
  const posts = await getAllPosts();
  return posts.filter((post) => post.featured);
}

export async function getNonFeaturedPosts(): Promise<Post[]> {
  const posts = await getAllPosts();
  return posts.filter((post) => !post.featured);
}

먼저 getAllPosts라는 함수를 통해 전체 posts 데이터를 받아온 후

getNonFeaturedPosts함수에서 filter메서드를 통해 featured에 false 값이 할당된, 즉 non featured Posts만 필터 되도록 했다.

컴포넌트에서 읽어 오기

components 폴더에 PostsCarousel.tsx 컴포넌트를 생성해 캐러셀을 컴포넌트화 했다.

그리고 비즈니스 로직에서 작성한 getNonFeaturedPosts함수를 가져와 데이터를 읽어오도록 했다.

src/components/PostsCarousel.tsx

import { getNonFeaturedPosts } from "@/service/posts";
import PostCard from "./PostCard";

export default async function PostsCarousel() {
  const posts = await getNonFeaturedPosts();

  return (
    <section className="my-4 p-7">
      <h2 className="text-2xl font-bold my-2">You May Like</h2>  
       {posts.map((post) => {
          return <PostCard key={post.path} post={post} />;
       })}
    </section>
  );
}

react-multi-carousel 사용

공식 문서의 예제는 다음과 같다

import Carousel from "react-multi-carousel";
// 라이브러리 import
import "react-multi-carousel/lib/styles.css";
// css import
const responsive = {
  // 반응형 설정 
  superLargeDesktop: {
    // 이름은 마음대로 
    breakpoint: { max: 4000, min: 3000 },
    items: 5
  },
  desktop: {
    breakpoint: { max: 3000, min: 1024 },
    items: 3
  },
  tablet: {
    breakpoint: { max: 1024, min: 464 },
    items: 2
  },
  mobile: {
    breakpoint: { max: 464, min: 0 },
    items: 1
  }
};
<Carousel responsive={responsive}>
  <div>Item 1</div>
  <div>Item 2</div>
  <div>Item 3</div>
  <div>Item 4</div>
</Carousel>;

라이브러리를 import 한 후
필요하면 반응형을 설정하고
Carousel이라는 컴포넌트로 carousel 안에 보여줄 아이템들을 감싸주면 된다.

원래는 swiper라는 라이브러리를 사용했었는데 업데이트가 되면서
용량이 너무 커져서 이 라이브러리를 선택했다.

MultiCarousel.tsx 컴포넌트

재사용성과 클린 코드를 고려해 라이브러리 사용하는 부분도 따로 컴포넌트화했다.

src/components/MultiCarousel.tsx

'use client'
// 브라우저에서 자동으로 스크롤링 되는 부분
// 버튼을 눌렀을 때 이동하는 부분
// 이 있기 때문에 서버컴포넌트가 아니라 클라이언트 컴포넌트로 만들어야함

import Carousel from "react-multi-carousel";
import "react-multi-carousel/lib/styles.css";

const responsive = {
  superLargeDesktop: {
    breakpoint: { max: 4000, min: 3000 },
    items: 4
  },
  desktop: {
    breakpoint: { max: 3000, min: 1024 },
    items: 4
  },
  tablet: {
    breakpoint: { max: 1024, min: 464 },
    items: 3
  },
  mobile: {
    breakpoint: { max: 464, min: 0 },
    items: 2
  }
};

type Props = {
  children: React.ReactNode;
  // prop으로 받아오는 children의 타입을 지정할 때 
  // React의 ReactNode라고 지정해주면 된다.
};

export default function MultiCarousel({ children }: Props) {
  return (
    <Carousel 
    // 내가 지정하고 싶은 option들을 prop으로 지정
    infinite // 무한정
    autoPlay // 자동 play
    responsive={responsive} // 위에서 정의한 responsive
	itemClass="m-2" // 각 아이템 별로 class 지정 
	>
      {children}
    </Carousel>
  );
}

CarouselPosts.tsx에서 MultiCarousel.tsx 사용

CarouselPosts는 기본적으로 서버 컴포넌트이다.
따라서 클라이언트 컴포넌트가 아닌 부분들은 서버에서 처리를 하고
실제로 캐러셀을 보여주는 부분은 클라이언트 컴포넌트로 브라우저에서 처리하도록 되어있다.

이처럼 클라이언트 컴포넌트를 필요로 하는 부분이 있다면
전체 페이지는 클라이언트 컴포넌트로 만드는 것이 아니라
그 부분만 최소한의 단위로 만들어서 따로 만들어 사용하는 것이 중요하다.

src/components/PostsCarousel.tsx

import { getNonFeaturedPosts } from "@/service/posts";
import MultiCarousel from "./MultiCarousel";
import PostCard from "./PostCard";

export default async function PostsCarousel() {
  const posts = await getNonFeaturedPosts();

  return (
    <section className="my-4 p-7">
      <h2 className="text-2xl font-bold my-2">You May Like</h2>
      <MultiCarousel>
    	// 캐러셀 컴포넌트를 가져와 아래 posts들을 감싸준다
        {posts.map((post) => {
          return <PostCard key={post.path} post={post} />;
        })}
      </MultiCarousel>
    </section>
  );
profile
룰루랄라 개발일지🎶❤️‍🔥🧑‍💻❤️‍🔥🎵

0개의 댓글