DogKaeBi

[Next.js 블로그] 데이터 컨트롤러. 카드 수량 제어

getCardData controller를 만들어서. 데이터 종류를 추출해 한 페이지 당 보여주는 카드의 수량을 제한해 보기

[Next.js 블로그] 데이터 컨트롤러. 카드 수량 제어

기존 진행된 내용

이전 참고 내용

[카드 리스트 기본틀]
[카드 리스트 grid]
[한자 카드]
[블로그 카드]
[블로그 카드 이미지]
[페이지별 다른 카드 리스트]

/cantonese 한자 페이지
/cantonese/word 단어 페이지
/blog 블로그 페이지

3개 페이지에서 CardList 를 사용했다.
각 페이지에서 타입과 데이터를 전달해서
CardList에서 grid 디자인을 조절하고,
CnCardBlogCard를 선택했다.


이번 계획

한 페이지에 카드의 수량을 제한하고 싶다.

controller폴더를 따로 만들어서
getCardData.js를 생성해서
보여줄 카드를 제어할 계획이다.

제어할 내용은
데이터의 종류수량이다.

이번 관련된 내용

  • javascript 배열 sort() 함수
  • javascript 배열 filter() 함수
  • javascript 배열 slice() 함수
  • javascript 남은 수 % 연산


getCardData 만들기

getCardData.js 파일 생성

// .\app\controller\getCardData.js

export function getCardData() {
  return [];
}

export 내보내기를 해야
다른 곳에서 사용할 수 있다.

기능 계획

/cantonese/page.js 한자 페이지
/cantonese/word/page.js 단어 페이지
/blog/page.js 블로그 페이지

CardList와 동일하게 위 3개 페이지에서 사용될 것이다.

필요한 내용(변수)은

  • 데이터
  • 현재 페이지
  • 한 페이지 최대 카드 수량
  • 현재 태그 ( SubNav 내용 [서브nav 편]참고 )

데이터에서 카테고리를 구분해서
필요한 페이지의 카드를
최대 수량만큼 return 할 생각이다.


기능 구현

방법이 여러개 생각난다.
getCardData에서 전부 처리하는 방법,
데이터를 전달하는 방법,
데이터의 해당 카테고리만 분리해서 전달하는 방법...

하지만 우선 기능은 같기 때문에
하나로 작성하기로 했다.

// .\app\controller\getCardData.js

export function getCardData(category, pageNum, maxCardInPage) {
  const data = getCategoryData(category);
  const dataLength = data.length;
  const isFullCard = dataLength - pageNum * maxCardInPage >= 0;
  const cardLength = isFullCard ? maxCardInPage : dataLength % maxCardInPage;
  const startCardNum = (pageNum - 1) * maxCardInPage;
  const endCardNum = startCardNum + cardLength;
  return data.slice(startCardNum, endCardNum);
}

function getCategoryData(category) {
  if (category == "tc") return getTcData();
  if (category == "word") return getWordData();
  if (category == null) {
    return getBlogData()
  } else{
    return getBlogData().filter((post) => post.category == category)
  }
}

function getBlogData() {
  const tempBlog = [
    { date: "2024-01-01 00:00:00", category: "coding" title: "1", desc: "설명1", slug: "1" },
    { date: "2024-01-02 00:00:00", category: "coding" title: "2", desc: "설명2", slug: "2" },
    { date: "2024-01-03 00:00:00", category: "coding" title: "3", desc: "설명3", slug: "3" },
    { date: "2024-01-04 00:00:00", category: "cantonese" title: "4", desc: "설명4", slug: "4" },
    { date: "2024-01-05 00:00:00", category: "cantonese" title: "5", desc: "설명5", slug: "5" },
    { date: "2024-01-06 00:00:00", category: "cantonese" title: "6", desc: "설명6", slug: "6" },
    { date: "2024-01-07 00:00:00", category: "daily" title: "7", desc: "설명7", slug: "7" },
    { date: "2024-01-08 00:00:00", category: "daily" title: "8", desc: "설명8", slug: "8" },
    { date: "2024-01-09 00:00:00", category: "daily" title: "9", desc: "설명9", slug: "9" },
  ];

  return tempBlog.sort((a,b) => b.date - a.date);
}

예시
getCardData getCategoryData getBlogData 5개의 함수를 만들었다.
(getTcData, getWordData 생략)

getCardData을 외부에서 사용할 것이고,
다른 함수들은 getCardData 내부에서 사용될 것이다.

getCategoryData은 간단하다.
category를 체크하고 데이터를 get한다.


getCategoryData: 배열 sort 함수

// .\app\controller\getCardData.js - getCategoryData
function getBlogData() {
  const tempBlog = [
    ...
  ];

  return tempBlog.sort((a,b) => b.date - a.date);
}

아직 DB결정을 하지 않고
getter를 만들지 않아서...
getBlogData함수를 만들어서
전에 만들었던 임시 데이터를 사용했다.

sort함수를 사용해서 최신순으로 정열해서 return 했다.


getBlogData: 배열 filter 함수

// .\app\controller\getCardData.js - getCategoryData

function getCategoryData(category) {
  if (category == "tc") return getTcData();
  if (category == "word") return getWordData();
  if (category == null) {
    return getBlogData();
  } else {
    return getBlogData().filter((post) => post.category == category);
  }
}

getCategoryData함수는 category를 받는다.
category를 체크해서 다른 get함수를 호출한다.
blog 데이터의 경우, 카테고리가 있으면
filter를 사용해서 해당 내용만 return했다.


getCardData: 배열 slide 함수

// .\app\controller\getCardData.js - getCardData

export function getCardData(category, pageNum, maxCardInPage) {
  const data = getCategoryData(category);
  const dataLength = data.length;
  const isFullCard = dataLength - pageNum * maxCardInPage >= 0;
  const cardLength = isFullCard ? maxCardInPage : dataLength % maxCardInPage;
  const startCardNum = (pageNum - 1) * maxCardInPage;
  const endCardNum = startCardNum + cardLength;
  return data.slice(startCardNum, endCardNum);
}

현 카테고리 : category,
현재 페이지 : pageNum,
최대 카드수 : maxCardInPage
을 받는 함수이다.

const data = getCategoryData(category);

getCategoryData를 호출해서
해당 카테고리의 데이터를 받았다.


const dataLength = data.length;

해당 데이터의 길이를 보고


const isFullCard = dataLength >= pageNum * maxCardInPage;
const cardLength = isFullCard ? maxCardInPage : dataLength % maxCardInPage;

현재 페이지에 남은 카드의 수량이 최대 카드수량 만큼 있는지 확인하고...
참이면 최대 카드수를, 거짓이면 남은 수량을 확인했다.


const startCardNum = (pageNum - 1) * maxCardInPage;
const endCardNum = startCardNum + cardLength;

배열 시작과 끝을 확인하고


return data.slice(startCardNum, endCardNum);

해당되는 데이터를 전달했다.



결과보기

Blog 페이지에 적용하기

import Heros from "./components/Heros";
import SubNav from "./components/SubNav";
import CardList from "./components/CardList";
import { getCardData } from "./controller/getCardData";

export default function Blog(props) {
  const tag = props.searchParams.tag; // SubNav 편에서 만들음
  const page = props.searchParams.page ?? 1;
  const maxCardInPage = 6;
  const blogData = getCardData(tag, page, maxCardInPage);

  return (
    <>
      <Heros path="blog" />
      <SubNav path="blog" slug={tag ?? ""} />
      <CardList path="blog" data={blogData} />
    </>
  );
}
  • [SubNav편]에서 만들었던 props를 사용해서 tagpage를 확인한다.
  • page는 없는 경우 1로 사용했다.
  • maxCardInPage는 6으로 설정했다. (6개/페이지)
  • getCardData로 데이터를 받았다.

결과

원하는 결과가 나온다.
지금 임시 데이터는 모두 9개이지만
maxCardInPage인 6개만 나온다.

SubNav로 다른 태그를 클릭하면
각 3개도 잘 나온다.

하지만 아직 pagination이 없어서 페이지를 이동할 수 없다.
우선 테스트를 위해서 브라우저 주소로 ?page=2를 사용했다.

전체링크 : http://localhost:3000/cantonese?page=2

이도 남은 3개의 카드가 잘 나온다.