Layout 컴포넌트에 속한 네비게이션 메뉴를 만들었었다.
처음 작성한 코드는 아래와 같다.
만약, 위 코드와 같이 작성하게 되면 네비게이션 바에 버튼이 하나씩 추가될 때마다
함수 작성, props전달, 타입 작성 등 굉장히 수고스러워진다.
또한, 사진에서는 alert처리 되어있지만 결국 모든 메뉴 버튼 클릭 시에 발생하는 동작은 해당 페이지로의 이동이다.
따라서, 보다 더 간결하고 유지보수가 용이한 코드롤 작성하기 위해 노력했다.
1차적으로 버튼을 눌렀을 때 연결할 각 페이지 폴더이름을 id로 지정해주었다.
이렇게 두고 보니, 각 버튼을 위해 만들어진 3개의 함수가 너무나도 같은 기능을 수행했다.
이러한 상황이라면 "/boards","/markets","/mypage" 를 원소로 가지는 배열을 만들어서 map을 사용하면 메뉴 아이템 생성이 훨씬 단순해질 것이다.
그러나, 우리는 각 페이지를 뜻하는 주제를 명시해줘야한다. (자유게시판, 중고마켓 등)
따라서 객체를 사용해서 이름과 페이지 둘 다 전달을 해주었다.
아래는 리팩토링 후 최종 코드이다. 코드가독성이 눈에 띄게 향상되고, 아이템을 추가하려면 단순히 NAVIGATION_ITEM 배열에 객체를 하나만 추가해주면 되기 때문에 유지보수도 용이하다.
페이지 처리를 하는 방법에는 크게 일반적인 방식(화살표 버튼)과 스크롤 방식, 2가지 방법이 있다.
이번에는 일반적 방식의 페이지 처리, 즉 페이지네이션 방식을 알아보자.
페이지 번호를 클릭해서 이동하는 방식의 페이지 처리 방법입니다.
아래와 같이 게시판 형태의 페이지에서 가장 일반적으로 사용되는 방식입니다.
사용자들은 페이지네이션을 일상적으로 사용하고 있기 때문에 인식하지 못하지만,
사실 페이지네이션 처리를 위해서는 다양한 것을 고려해주어야 한다.
가장 먼저 fetchBoards API를 활용해서 게시글 목록을 불러온다.
// gql query
const FETCH_BOARDS = gql`
query fetchBoards($page: Int) {
fetchBoards(page: $page) {
_id
writer
title
}
}
`;
// fetchBoards
const { data } = useQuery(FETCH_BOARDS, { variables: { page: 1 } });
return (
<div>
{data?.fetchBoards?.map((el) => (
<div key={el._id}>
{el.title} {el.writer}
</div>
))}
<span> 1 </span>
<span> 2 </span>
<span> 3 </span>
</div>
)
위와 같이 작성하면, 첫 번째 페이지에 등록되어 있는 게시물 데이터를 받아와서 렌더링한다.
이를 활용하면 페이지 번호를 클릭하면 해당 페이지 번호에 해당하는 게시물 목록을 보여주는 기능도 구현할 수 있다.
먼저, 페이지 번호를 클릭했을 때 실행할 함수를 아래와 같이 작성했다.
const onClickPage = (event: MouseEvent<HTMLSpanElement>): void => {
refetch({ page: Number(event.currentTarget.id) });
};
return(
...
{new Array(10).fill(1).map((_, index) => (
<span
key={index + 1}
id={String(index + 1)}
onClick={onClickPage}
style={{ cursor: "pointer", padding: "0px 10px" }}
>
{index + 1}
</span>
))}
)
new Array를 사용하여 크기가 10인 배열을 생성 후 임의 값으로 채운다.(이때, index를 사용할 것이기 때문에 1이 아니라 어떤 값이 들어와도 상관없다)
각 페이지번호 span태그에 id속성을 달아주고, index+1(페이지 번호) 값을 지정해준다.
이렇게 하면, event.currentTarget.id로 선택한 페이지 번호를 받아올 수 있게 된다.
이를 토대로 refetch 함수를 통해 리렌더링 해준다.
사실, 이 방법 말고도 아래 코드와 같이 여러 방법이 존재한다.
//1번 방법(index 활용)
{[1, 1, 1, 1, 1].map((_, index) => (
<span key={index+1} id={String(index+1)} onClick={onClickPage}>
{index+1}
</span>
))}
//2번 방법(el활용)
{[1, 2, 3, 4, 5].map((el, index) => (
<span key={el} id={String(el)} onClick={onClickPage}>
{el}
</span>
))}
//3번 방법(손수 하나씩 제작..)
<span id="1" onClick={onClickPage}></span>
<span id="2" onClick={onClickPage}></span>
<span id="3" onClick={onClickPage}></span>
map 특성상 element와 index를 받아올 수 있는데 만약 둘 중 하나만 쓰인다면 쓰이지 않는 곳에
_(언더바)를 작성해주는 것이 관례다.
❗refetchQueries와 refetch의 차이점?
refetchQueries
는 뮤테이션을 실행한 후에 특정 쿼리들을 다시 가져오는 데 사용됩니다.
(변경 사항을 화면에 즉각적으로 반영하기 위함)
refetch
는 단순히 특정 GraphQL 쿼리를 다시 가져오는 데 사용됩니다. (언제든 사용)
refetch는 메서드로 사용되고, refetchQueries는 뮤테이션 옵션의 속성(property)으로 사용
const [updateUser] = useMutation(UPDATE_USER_MUTATION, {
refetchQueries: [{ query: GET_USER_QUERY, variables: { id: userId } }],
});