개발자
혹시 next.js에서 스크롤 유지 (뒤로가기 시, 전 페이지의 스크롤 유지) 기능을 구현해보신 분 계신가요? next.js에서 실험적으로 설정을 켜면 되는 것 같긴한데 (https://mmazzarolo.com/blog/2021-04-10-nextjs-scroll-restoration/), 뭔가 실험적인 기능인 것 같아서 써도 되는지 잘 모르겠어서요. 혹시 깡(?) js로 구현해보신 능력자분 있으시면 지나가면서 아이디어 한번씩 부탁드립니다. (보통 이렇게 깡?으로 구현하는게 좋은건가요? 아니면 지양해야할까요?)
답변 3
인기 답변
비슷한 기능을 구현해본 적이 있긴하지만, 질문자님의 웹 사이트 동작 방식이 어떤지 몰라서 명확한 답을 드릴 순 없을 것 같네요 😟 일단 질문자님이 공유해주신 링크의 원문 중 참조한 링크(https://github.com/vercel/next.js/commit/38bd1a024cb25923d8ea15f269a7294d073684d8)를 보시면 next.js에서 해당 기능을 어떻게 구현했는지 볼 수 있네요. 저라면 요거 좀 더 살펴보고 현재 웹 사이트에 적용했을때 문제 없는지 파악하는데부터 시작할 것 같아요. 일단 막연하게 생각해보면, next.js를 어떻게 사용하는지에 따라서 기능 구현 방법이 달라질 수 있습니다. 예를 들면, 인피니트 스크롤 형식의 페이지에 react-query와 pagination을 적용해서 데이터를 불러오는 페이지의 경우, 뒤로가기를 통해 재방문했을 때 전에 요청했던 pagination page의 데이터까지 보존하고 있어야 DOM의 크기도 그만큼 커질 수 있고 스크롤이 내려갈 수 있겠죠? react-query와 SSR을 사용하신다면 요청한 key의 데이터가 의도치않게 갱신되는 것도 신경 쓰셔야할거구요. 질문자님의 웹 사이트가 어떤 방식으로 돌아가는지 구체적이지 않아서 명확한 답을 드리기는 어렵지만, 시간이 되신다면 공식 문서, 다른 기술 블로그, 스택오버플로우를 찾아보시면서 생각해보시면 좋을 것 같습니다. 개인적으로는 깡으로 구현하는 것보다 라이브러리가 있다면 쓰자 주의긴한데, 이건 상황에 따라 다를 것 같아요 참고로 "커리어리 사이드 프로젝트 페이지" (https://careerly.co.kr/lounge/side-projects)에 스크롤 유지가 적용되어 있는데 CSR과 next.js의 스크롤 유지 기능을 살짝 손봐서 만들었습니다 🙂
익명
작성자
2022년 09월 16일
생각보다 고려해야될게 많네요. 역시 쉽지는 않군요. 참고자료 열심히 찾아볼게요. 답변 감사드립니다!
이방원
아스크스토리디에스 프론트엔드 개발자 • 2023년 04월 24일
작성된지 오래된 글이지만, "커리어리 사이드 프로젝트 페이지"의 스크롤 유지 기능을 살펴보고 저 나름대로 살펴보았는데, 글 리스트에 클릭하고 페이지가 이동하기 전에, session storage 특정 글 리스트의 index값을 set -> 게시글 리스트 페이지로 돌아갔을 때, 글 리스트 데이터를 전부 불러오고, -> session storage에 저장된 index 값을 get해서 scroll 위치를 찾아준 다음 -> session storage에 index 값을 저장했던 key에 null 값을 set한다 라고 생각했습니다. 여기서 궁금한 게 있습니다. 정현 님께서 말씀하신 무한 스크롤 형식의 페이지(reaact query와 페이지네이션을 적용)에서 ssr을 사용하였을 때, 요청한 key의 데이터가 의도치 않게 갱신 된다는 것에 대한, 원인에 대해 궁금합니다!!
손정현
엔지니어 • 2023년 04월 25일
방원님 안녕하세요! 현재 사이드프로젝트 페이지는 방원님이 파악하신것처럼 무한 스크롤 컴포넌트의 index를 사용하는 방식으로 변경된 상태입니다. 기존에는 scroll height을 저장해놓고 불러오는 로직이었어요 :) (기억을 더듬어서) react-query와의 문제를 설명드리자면 일종의 엣지 케이스였던걸로 기억하구요, 구성을 설명드리자면 사이드 프로젝트 목록 데이터를 getServersideProps에서 queryClient.prefetchQueries로 가져오고 있었고 디폴트 limit이 걸려있었습니다. 마찬가지로 클라이언트 사이드에서 스크롤을 내리면 요청을 날릴 수 있도록 구현되어 있었구요. 서버와 클라이언트 모두 같은 query key를 사용하고 있었어요. 유저가 page 5까지 내렸다가 다른 페이지로 이동/새로고침을 한 뒤 뒤로가기를 하면 getServersideProps가 다시 돌았던걸로 기억합니다. 그래서 디폴트 리밋이 걸려있는 queryClient가 클라이언트로 덮어씌워지면서 기존 page 5까지 받아온 데이터가 날라갔던 현상이었어요. 사용하던 버전은 아마 next 11이랑 react-query v3 였던걸로 기억해요. 적고보니까 이게 정확한 원인이었는지도 살짝 의문이긴하네요. 저때쯤에 제가 react-query 깃허브 질문을 올린적이 있는데 메인테이너 분이 nextjs에서 이런거 하기 좀 힘들수있다라고 했었던 것 같네요. - https://github.com/TanStack/query/discussions/3783#discussioncomment-3392263
이방원
아스크스토리디에스 프론트엔드 개발자 • 2023년 04월 25일
안녕하세요 정현 님!! 답변 주셔서 감사합니다!! 덕분에 재미있는 에피소드 하나 듣게 되었습니다. 아직 react-query에 대해서 잘 모르고 getServersideProps에 대해서도 잘 몰라, 검색하면서 주신 답변을 읽어보았습니다. getServersideProps가 다시 도는 부분에서 고민을 해야 하는 걸까? queryClient.prefetchQueries를 사용해도 서버에서 새로 데이터를 다 가져오는 경우인가? 그래서 새로운 데이터로 인해 덮어 씌어지는 건가? default limit을 스토로지를 사용해 page 늘어 날 때마다 바꿀 수 있다면 좋을까? 라는 상상을 해보기도 했습니다. 읽으면서 더 배우고 생각하게 되었습니다. 감사합니다!!
안녕하세요! Next.js에서 스크롤 유지 기능을 구현하는 방법은 다양하지만, 가장 간단한 방법은 다음과 같습니다. 1. _app.js 파일에 scrollRestoration 설정 추가 2. 아래 코드에서 'scrollRestoration'을 'manua'l로 설정하고, 'cachedScrollPositions' 객체를 통해 각 페이지별 스크롤 위치를 기억합니다. 3. 'beforeunload' 이벤트를 통해 페이지 이동 시점에 스크롤 위치를 저장하고, 'routeChangeComplete' 이벤트를 통해 이전 페이지의 스크롤 위치를 찾아와 복원합니다. 이 방법을 사용하면 실험적인 기능을 켜지 않고도 간단하게 스크롤 유지 기능을 구현할 수 있습니다. 하지만, 이 방법은 페이지 이동 시점마다 스크롤 위치를 저장하므로 메모리 사용량이 증가할 수 있습니다. 이 문제를 해결하기 위해 스크롤 위치 저장을 로컬 스토리지나 쿠키를 사용하여 관리할 수도 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
import { useEffect } from 'react'; import { useRouter } from 'next/router'; function MyApp({ Component, pageProps }) { const router = useRouter(); useEffect(() => { // 뒤로가기 시 스크롤 위치를 이전 위치로 복원 if ('scrollRestoration' in history) { history.scrollRestoration = 'manual'; const cachedScrollPositions = {}; const onBeforeUnload = () => { cachedScrollPositions[window.location.pathname] = [window.scrollX, window.scrollY]; }; window.addEventListener('beforeunload', onBeforeUnload); const onRouteChangeStart = () => { cachedScrollPositions[router.pathname] = [window.scrollX, window.scrollY]; }; router.events.on('routeChangeStart', onRouteChangeStart); const onRouteChangeComplete = (url) => { if (cachedScrollPositions[url]) { setTimeout(() => window.scrollTo(...cachedScrollPositions[url]), 0); } }; router.events.on('routeChangeComplete', onRouteChangeComplete); return () => { window.removeEventListener('beforeunload', onBeforeUnload); router.events.off('routeChangeStart', onRouteChangeStart); router.events.off('routeChangeComplete', onRouteChangeComplete); }; } }, [router]); return <Component {...pageProps} />; } export default MyApp;
커리어리 AI 봇의 답변을 평가해 주세요!
지금 가입하면 모든 질문의 답변을 볼 수 있어요!
현직자들의 명쾌한 답변을 얻을 수 있어요.
이미 회원이신가요?
지금 가입하면 모든 질문의 답변을 볼 수 있어요!