TIL[14일차].페이지네이션, state 끌어올리기

남예지·2022년 11월 17일
0

TIL

목록 보기
10/47
배운 리팩토링 방법들
1. early-exit
2. toggle
(new!)3. 비슷한 기능(함수) 묶기

백앤드에서 받아온 데이터는 객체가 배열안에 들어가있는 형태

페이지네이션

페이지네이션이란 페이지번호를 클릭해서 이동하는 방식의 페이지 처리방법이다.
게시글 목록을 페이지네이션으로 설정하기
스크롤 방식도 페이지네이션이다.

게시글 불러오기

페이지네이션을 만들때 고려해야 하는 부분
우선 게시글 목록을 map으로 불렀다면 map 아래쪽에 페이지네이션을 작성한다.
그리고 클릭 시 작동할 함수도 onClick에 바인딩해준다.
함수 안에서는 페이지를 조회해야 하기 때문에 refetch() 를 해줘야한다.
그러면 page값을 넘겨야한다. 위에 fetch boards query에서 페이지를 받아온다.

이걸 map과 refetch를 이용해 리팩토링 해보았다.

이전페이지 / 다음페이지

일단 장소는 아까 게시글 페이지네이션의 앞뒤로 들어가줘야하니 span으로 만들어준다.
그리고 span 안에는 클릭 시 이전/다음 페이지로 넘어갈 수 있는 함수를 넣어주기 위해
onClick을 넣어준 뒤 함수를 만들어 바인딩해 준다.

  const onClickPrevPage = () => {
  };

  const onClickNextPage = () => {
  };
  
      <span onClick={onClickPrevPage}>이전페이지</span>
      {/* 실무에서는 el을 안쓰면 안쓴다는 의미로 _ 를 넣는다. */}
      {new Array(10).fill(1).map((_, index) => (
        <span
          key={index + 1}
          id={String(index + 1)}
          onClick={onClickPage}
          style={{ margin: "10px" }}
        >
          {index + 1}
        </span>
      ))}
      <span onClick={onClickNextPage}>다음페이지</span>

함수 안에는 눌렀을 때 10페이지 뒤/앞으로 가야하기에 useState에 startPage를 기본값 1로 저장하고 누를때마다 10페이지씩 늘어가는 값을 저장하게 해준다. 그리고 이를 refetch해줘야한다.
코드는 아래와 같다.

const [startPage, setStartPage] = useState(1);

const onClickPage = (event: MouseEvent<HTMLSpanElement>) => {
    //기다려야하면 async/await 하면 된다.
    void refetch({ page: Number(event.currentTarget.id) });
  };
  
const onClickPrevPage = () => {
    setStartPage((prev) => prev - 10);
    void refetch({ page: startPage - 10 });
  };

  const onClickNextPage = () => {
    setStartPage((prev) => prev + 10);
    void refetch({ page: startPage + 10 });
    // setStartPage(startPage + 10) 해도 동일하다
  };

그러니 아까 map으로 게시글 목록을 부를 때 + 1 했던걸 startPage로 바꿔준다.

<span onClick={onClickPrevPage}>이전페이지</span>
      {/* 실무에서는 el을 안쓰면 안쓴다는 의미로 _ 를 넣는다. */}
      {new Array(10).fill(1).map((_, index) => (
        <span
          key={index + startPage}
          id={String(index + startPage)}
          onClick={onClickPage}
          style={{ margin: "10px" }}
        >
          {index + startPage}
        </span>
      ))}
      <span onClick={onClickNextPage}>다음페이지</span>

여기서 문제는 이전 페이지를 계속 누르다보면 없는 페이지도 계속 나오는데 이를 방지해줘야한다.
startPage가 1일 때 이전페이지를 못누르게 하면 이전페이지로 계속 넘어가는 문제는 해결된다.
그런데 다음페이지로 넘어갈 때는 마지막 페이지를 알아야한다.
만약 105페이지가 마지막 페이지라고 하면 110까지만 보여주고 이후에는 다음페이지가 나오면 안된다.
startPage +10 가 lastPage보다 크면 다음페이지가 비활성화되게 한다.

const onClickPrevPage = () => {
    if (startPage === 1) return;
    setStartPage(startPage - 10);
    void refetch({ page: startPage - 10 });
  };

  const onClickNextPage = () => {
    if (startPage + 10 <= lastPage) {
      setStartPage(startPage + 10);
      void refetch({ page: startPage + 10 });
    }
  };
  
  <span onClick={onClickPrevPage}>이전페이지</span>
      {new Array(10).fill("철수").map(
        (_, index) =>
          index + startPage <= lastPage && (
            <span
              key={index + startPage}
              id={String(index + startPage)}
              onClick={onClickPage}
              style={{ margin: "10px" }}
            >
              {index + startPage}
            </span>
          )
      )}
  • refetch에 오류 문구는 void를 앞에 붙이면 해결되는데 만약 promise를 리턴한다면 void 대신 async/awite 를 하고, 기다릴 필요가 없으면 void를 한다.

자식 state를 부모 state로 끌어올리기

자식이 부모의 state를 변경하거나 state를 넘겨주는 방법

부모 컴포넌트의 setState를 받아 변경하고 사용할 수 있다.
동일한 데이터에 대한 변경 사항을 여러 컴포넌트에 반영해야 할 경우 사용한다.


-실습-
파일을 총 3개 만들어서 부모 컴포넌트 하나와 자식 컴포넌트 2개(형제)를 만들어준다.

// 부모 컴포넌트 
import { useState } from "react";
import Chlid1 from "../../src/components/units/14-lifting-state-up/child1";
import Chlid2 from "../../src/components/units/14-lifting-state-up/child2";

export default function CounterStatePage() {
  // let count = 10
  const [count, setCount] = useState(0);

  // 부모의 state 조작 방법 - 1번째
  function onClickCountUp() {
    setCount((prev) => prev + 1);
  }

  return (
    <>
      <Chlid1
        count={count}
        // onClickCountUp={onClickCountUp}
        setCount={setCount}
      />
      <div>============================</div>
      <Chlid2 count={count} onClickCountUp={onClickCountUp} />
    </>
  );
}
// 자식1 컴포넌트
export default function Chlid1(props) {
  // 부모의 state 조작 방법 - 2번째
  const onClickChild1 = () => {
    props.setCount((prev: number) => prev + 1);
  };

  return (
    <div>
      <div>자식 1의 카운트: {props.count}</div>
      <button onClick={onClickChild1}>카운트 올리기!!!</button>
      {/* <button onClick={props.onClickCountUp}>카운트 올리기!!!</button> */}
    </div>
  );
}
// 자식2 컴포넌트
export default function Chlid2(props) {
  return (
    <div>
      <div>자식 2의 카운트: {props.count}</div>
      <button onClick={props.onClickCountUp}>카운트 올리기!!!</button>
    </div>
  );
}

예시를 통해 부모의 state조작방법에는 2가지가 있다는 것을 알 수 있다.
자식 1도 자식 2처럼 써도 부모 컴포넌트에 onClickCount만 props해주면 아무런 문제가 없다.

버튼을 어디를 누르든 같이 숫자가 올라가는 걸 볼 수 있다.

==================================================
오늘 수업은 패이지를 넘기는 페이지네이션과 스테이트를 끌어올려 부모 컴포넌트에서 자식 컴포넌트로 동일한 데이터를 공유하는 스테이트 끌어올리기를 배웠다.
뭔가 페이지네이션에 게시물 각각의 데이터가 들어가면 코드가 더 길어질 것 같은데 이것도 그럼 구조를 나눠보면 좋을 것 같다.
하루하루 뇌에 새로운 자료가 들어온다.
머리가 무거워지는 느낌. 하지만 이거 다 기초겠지? 열심히 해야겠다.

profile
총총

0개의 댓글