카테고리나 특정 필터 값을 선택하도록 하면, url에 해당 값이 출력되게 하는 경우가 있다.
데이터를 추가한 Url로 다른 페이지에서 해당 데이터를 뽑아 사용할 수도 있다.
하지만 한 가지 문제가 있었다.
useSearchParams
와 route/navigation
라이브러리의 route.push
나 route.replace
를 사용하여 url을 변경하게 되면 하드 새로고침이 되어 페이지 전체가 리렌더링이 된다.
이번 포스트는 위의 문제를 해결한 과정을 담아보려 한다.
route/navigation
의 route...
사용하여 url 변경 시 페이지 이동이 없더라도 새로고침되어 페이지 전체 리렌더링되는 문제
이는 같은 페이지에서 사용자가 선택한 데이터를 url에 선택한 데이터를 담게 했을 때 발생한다.
나는 카테고리를 선택하면, 선택한 데이터의 id를 url에 노출시켜주도록 했다.
그 결과, 위처럼 카테고리를 선택할 때마다 페이지 전체가 리렌더링되었다.
불필요한 부분까지 리렌더링이 진행되는만큼, 성능에 영향을 줄 수 있다.
router의 shallow routing을 사용하면 url만 변경되고 상태가 바뀌지 않는다.
이를 활용해서 리렌더링을 제어할 수 있다.
위의 글을 참고했다.
// 기존 코드
router.push(`/home?${newSearchParams.toString()}`);
// 수정한 코드
window.history.pushState({...window.history.state, as: newUrl, url: newUrl}, '', newUrl);
이렇게 수정하고 화면을 보니,
분명 url은 변경이 되고, 전체 새로고침도 되지 않는다.
하지만 또 다른 문제가, url만 변경이 되고 그에 대한 상태가 바뀌지 않는다는 것이다.
나는 useSearchParams
를 사용하여 url이 변경됨을 감지하고 그에 대응되는 데이터 값으로 상태를 변경시키도록 코드를 작성해두었다.
이는 window.history.pushState
를 사용하면 브라우저의 주소 표시줄은 변경되지만 Next.js 라우터 상태는 업데이트되지 않기 때문에 useSearchParams
가 변화에 반응하지 않는 문제이다.
카테고리에 대한 데이터는 Url에도 적용하지만, 전역 상태로도 저장해두고 다른 곳에서 사용 중이었기에 이 데이터를 활용하기로 했다.
전역 상태에 저장되어 있는 카테고리 데이터를 url이 변경될 때마다 상태가 바뀌어야 하는 컴포넌트에 추가해주었다.
const { setCategory, category: selectedCategory } = useCreateAgora(
useShallow((state) => ({
setCategory: state.setCategory,
category: state.category,
})),
);
const changeCategoryParams = useCallback(
(id: string) => {
if (pathname !== '/home') return;
const newSearchParams = new URLSearchParams(searchParams);
newSearchParams.set('category', isValidCategoryKey(id) ? id : '1');
newSearchParams.delete('q');
search.reset();
const newUrl = `/home?${newSearchParams.toString()}`;
window.history.pushState({...window.history.state, as: newUrl, url: newUrl}, '', newUrl);
},
[router, searchParams, pathname, selectedCategory],
);
기존엔 의존성 배열에 selectedCategory
를 넣어주지 않았다.
그래서 배열에 추가해주어 전역 상태가 바뀔 때마다 재실행하여 카테고리 버튼의 색상이 변경되도록 해주었다.
그리고 한 군데 더, 아고라 리스트를 출력하는 곳도 카테고리 값이 변경됨에 따라 같이 값에 따른 데이터를 호출해주어야 한다.
const { category: selectedCategory } = useCreateAgora(
useShallow((state) => ({
category: state.category,
})),
);
... (React Query)
queryKey: ['agoras', 'search', 'category', { ...searchParams, category: selectedCategory }],
...
나는 react-query를 사용하고 있기에 category 전역 상태가 변경됨에 따라 queryKey를 다르게 주도록 하였다.
이렇게 수정한 후, 화면을 보면
원하던 대로 변경되는 부분만 리렌더링이 진행된다!!
음식/여행 카테고리를 선택할 때 데이터가 출력되지 않는 부분은 데이터를 호출하는 데 있어서 지연이 발생한 것 같다.
로더가 보이도록 수정해야할 것 같다!