14일차 / Pagination, State lifting
13일차 코드리뷰
Body에 props.children,
< Layout >안에 props.childern(페이지 컴포넌트)이 들어간다.
yarn add @types/react-slick --dev
타입스크립트가 자바스크립트로 변형돼서 실행되므로 dev에 설치한다.
브라우저에 실행되는 부분은 dependencies,
실행되지 않는 부분은 devDependencise에 설치해야한다.
npm insatll --production 하면 dependencies에 있는 것들을 설치할 수 있다.
배포할 때 필요없는 것들을 설치할 필요 없으므로 가능하면 나눠서 설치하는 것이 좋음.
메뉴 코드 리팩토링
↑ 각각 온클릭 함수 줄 때
↑ onClick을 하나의 함수로 줄이는 과정
페이지네이션
api 서버 변경
_app.tsx, codegen.yaml의 url 바꾸기
types.ts도 최신화 필요 => yarn generate
페이지 출력
export default function MapBoardPage() {
const { data, refetch } = useQuery(FETCH_BOARDS);
const onClickPage = (event) => {
refetch({ page: Number(event.target.id) }); // variables 객체 , page는 숫자이므로 Number로 감싸줌
};
return (
<div>
{data?.fetchBoards.map((el) => (
<MyRow key={el._id}>
<MyColumn>{el.writer}</MyColumn>
<MyColumn>{el.title}</MyColumn>
</MyRow>
))}
<span onClick={onClickPage} id="1">
1
</span>
<span onClick={onClickPage} id="2">
2
</span>
<span onClick={onClickPage} id="3">
3
</span>
</div>
);
}
이렇게 받아오면 페이지가 100페이지가 넘어가면 어떻게 할 것인가? 하는 문제점이 생긴다.
{data?.fetchBoards.map((el) => (
<MyRow key={el._id}>
<MyColumn>{el.writer}</MyColumn>
<MyColumn>{el.title}</MyColumn>
</MyRow>
))}
{[1, 2, 3].map((el) => (
<span key={el} onClick={onClickPage} id={String(el)}>
{el}
</span>
))}
map을 활용하는 방법.
id에는 Number를 받아올 수 없고 el이 숫자값으로 입력되어있으므로 String으로 감싸준다.
index를 활용하는 방법.
안쓰는 것들은 언더바 처리를 한다. (관례)
이전페이지, 다음페이지
1페이지를 기준으로 잡고, 다음페이지 버튼을 클릭하면 1이라는 숫자를 더하기 10 해준다.
다음페이지를 누르면 index+11 이 나온다.
이전페이지는 index-10 해준다.
먼저 state를 잡아준다. (초기값 1)
const [startPage, setStartPage] = useState(1)
index에 StartPage를 더해준다.
{new Array(10).fill(1).map((_, index) => (
<span
key={index + startPage}
onClick={onClickPage}
id={String(index + startPage)}
>
{index + startPage}
</span>
))}
prev(이전 값)를 활용해 다음페이지는 +10, 이전페이지는 -10
const onClickNextPage = () => {
setStartPage((prev) => prev + 10);
};
const onClickPrevPage = () => {
setStartPage((prev) => prev - 10);
};
이렇게 했을 때 마지막 페이지보다 더 많은 페이지가 나오고,
마이너스 페이지가 나오게 된다.
어떻게 해결해야할까?
스타트 페이지가 1일때 이전페이지를 클릭하면 작동하지 않게 하면 된다.
const onClickPrevPage = () => {
if (startPage === 1) return;
setStartPage((prev) => prev - 10);
};
마지막 페이지가 몇페이지인지 계산해야함.
스타트페이지는 마지막 페이지까지만 나와야한다.
startPage <= lastPage
라스트 페이지는 어떻게 계산해야 할까?
게시글이 총 12개가 있으면 1페이지에 10개, 2페이지에 2개 나타난다.
총 게시글이 2페이지까지 있는 것.
12 -> 2page
35 -> 4page
앞 숫자보다 +1페이지가 된다.
12/10 -> 1.2
35/10 -> 3.5
60/10 -> 6.0
글 개수를 10으로 나눈 값에 올림을 해주면 된다.
query fetchBoardsCount를 이용해서 수를 가져오고 startPage <= lastPage 해준다!
const FETCH_BOARDS_COUNT = gql`
query fetchBoardsCount {
fetchBoardsCount
}
`;
const { data: dataBoardsCount } = useQuery(FETCH_BOARDS_COUNT)
const lastPage = Math.ceil(dataBoardsCount?.fetchBoardsCount /10 );
이미 data라는 이름을 사용했으므로 다른 이름을 선언하고,
lastPage를 선언해준다.
처음 값은 undefined이므로 ?를 넣어야한다.
const onClickNextPage = () => {
if (!(startPage + 10 <= lastPage)) return;
setStartPage((prev) => prev + 10);
};
예를 들어 start 페이지가 171이고 last 페이지가 173이면
start 페이지가 last 페이지보다 작을 때만 실행이 되어야한다.
이것의 반대일 때는 실행이 되면 안된다.
하지만 우리는 마지막 페이지인 173까지만 출력하고 싶다.
{new Array(10).fill(1).map((_, index) =>
index + startPage <= lastPage ? (
<span
key={index + startPage}
onClick={onClickPage}
id={String(index + startPage)}
>
{` `} {index + startPage}
</span>
) : (
<span></span>
)
)}
삼항연산자를 사용한 방법.
{new Array(10).fill(1).map(
(_, index) =>
index + startPage <= lastPage && (
<span
key={index + startPage}
onClick={onClickPage}
id={String(index + startPage)}
>
{` `} {index + startPage}
</span>
)
)}
&&연산자를 사용한 방법.
undefined를 출력하게 해도 빈값이 나오므로 가능하다.
페이지를 넘겨도 게시글이 바뀌지 않으므로 함수에 리패치를 추가해준다.
const onClickNextPage = () => {
if (!(startPage + 10 <= lastPage)) return;
setStartPage((prev) => prev + 10);
refetch({ page: startPage + 10 }); // variables 객체 , page는 숫자이므로 Number로 감싸줌
};
const onClickPrevPage = () => {
if (startPage === 1) return;
setStartPage((prev) => prev - 10);
refetch({ page: startPage - 10 }); // variables 객체 , page는 숫자이므로 Number로 감싸줌
};
State 끌어올리기
원래 우리가 쓰던 방식은 부모 컴포넌트에서 state를 props해서 사용하는 방식이었지만
자식들끼리 공유할 수는 없을까?
이렇게 하면 자식끼리 state를 공유할 수 있다.
이 상태에서 state를 바꾸면 자식들도 바뀐 state로 리렌더된다.
자식이 부모의 state를 바꾸고 싶으면?
부모가 가진setState를 넘겨주면 된다.
기본 틀 잡기
자식끼리 넘겨주려면 어떻게 해야하는가?
리액트는 데이터의 흐름이 단방향인것을 이용한다.
예시1
부모에 state를 넘겨주고, Child1, Child2를 리턴한다.
함수를 다 넘겨주고 props를 활용해 부모에서 자식에게로 넘긴다.
예시2
refetch가 다른곳에서 활용되고 있으므로 부모에게 끌어올려주어야한다.
Board에 refetch를 연결
Pagination에 refetch를 연결
완성
어디서든 재사용할 수 있는 Pagination 컴포넌트를 만들었다.
검색창도 같은 방식으로 만들 수 있다.
처음 만들 때는 시간이 걸릴 수 있지만, 공통 컴포넌트를 만들게 되면 개발이 훨씬 빨라진다.
Author And Source
이 문제에 관하여(14일차 / Pagination, State lifting), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@hhjk00/14일차저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)