지난주부터 회사 프로젝트에서 다른 팀원 분이 담당하던 feature를 내가 맡게 되었다. 인계를 받으면서 이슈 중 하나가 무한스크롤 기능 중 스크롤을 위로 올려 이전 페이지 아이템을 가져올 때 사용자가 현재 보고 있는 아이템이 화면에 유지되지 않고 새로 받아온 페이지의 첫번째 아이템으로 화면이 튀는 현상이었다. 반면 스크롤을 아래쪽으로 내려서 다음 페이지 아이템을 가져올 때는 현재 보고 있는 아이템이 화면에 그대로 유지되었다.
인계를 해준 팀원 분은 이 이슈를 스크롤 앵커링 문제라고 생각했고, 바닐라 JS를 사용하거나 React에서도 useRef를 사용해서 직접 DOM 조작을 할 때는 위쪽이나 아래쪽 어디로 스크롤을 하든지 스크롤 앵커링이 정상적으로 동작하며, React의 상태를 UI에 렌더링하는 경우 스크롤 앵커링이 정상적으로 동작하지 않는다는 이슈 리포트를 작성해서 인계해주었다.
하지만 코드를 직접 돌려본 결과, 무한스크롤 할 아이템을 담은 상태에 map 메소드를 돌려서 <Row /> 컴포넌트를 호출하는 과정에서 Row 컴포넌트의 key로 index를 사용하는 것이 문제였다. 인덱스를 key로 사용했기 때문에 이전 페이지 데이터를 요청해서 상태 배열의 앞부분에 새로운 데이터를 삽입하는 과정에서 항목의 순서가 바뀔 때 key 또한 바뀌게 되기 때문에 사용자가 현재 보고 있던 아이템이 뒤로 밀리고 새로 받아온 데이터가 그 자리를 대체하는 것이었다.
const [segments, setSegments] = useState([]);
// before
segments
.map((segment, index) => {
return <Row rowIndex={index} key={index} segment={segment} />;
})
// after
segments
.map((segment, index) => {
return <Row rowIndex={index} key={segment.id} segment={segment} />;
})
디버깅을 할 때 기본부터 차근차근 돌아봐야 한다는 걸 다시 한 번 생각하게 되었다.
📚 같이 읽으면 좋은 포스팅
'돌멩이 하나 > 에러는 미래의 연봉' 카테고리의 다른 글
React Query를 활용한 테이블에서 데이터 정렬하기 (0) | 2024.03.21 |
---|---|
React ErrorBoundary와 react-query를 사용하여 예외 처리 설계하기 (0) | 2024.03.10 |
ant design과 tailwind css 충돌 이슈 해결 (0) | 2023.09.04 |
styled-components에서 custom props 사용하기 (0) | 2023.07.28 |
[기능 구현 챌린지] 무한 스크롤 UI (0) | 2023.05.30 |