5. 무한스크롤의 문제점 및 해결방법

5.1 무한스크롤 문제점

자 이제 본격적으로 이렇게 만들어진 무한 스크롤의 문제점을 살펴보도록 하겠습니다. 일단 서버를 실행시키로 실행할 주소로 접속해 보면 다음과 같은 결과물을 볼 수 있을 것입니다.
화면을 보시면 스크롤은 이상없이 잘 작동하는 것을 볼 수 있습니다. 하지만 목록 중에서 하나를 클릭해 내용보기로 갔다가 브라우저의 뒤로가기를 클릭해 다시 리스트로 돌아오면 모든 리스트가 초기화 되어 처음 페이지가 보여지는 문제가 발생합니다. 이 말은 리스트를 이용해 수많은 페이지를 넘기다가 볼만한 내용이 있어 해당 부분을 클릭하고 다시 돌아오며 그 위치까지 또 다시 내려가야 다음 내용을 볼 수 있는 치명적인 문제가 발생하고 있는 것입니다.

[뒤로가기 문제 화면]

5.2 해결방법

자 그럼 이 문제를 한단계씩 해결해 보도록 하겠습니다. 우선 pub/sub을 이용해 리스트로 뿌려진 결과가 초기화 되지 않게 하는 부분부터 처리해보겠습니다. 위에서 설치 패키지 중에 meteorhacks:subs-manager 라는 패키지를 설치했는데요. 이녀석이 바로 일종의 subscriptions(구독)에 대한 캐쉬기능을 제공하는 페키지가 되겠습니다.

사용법은 아주 간단합니다. 다음파일을 열고 주석으로 처리된 부분을 추가 또는 수정하시면 됩니다.

client/contents/post-lists.js

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
Template.postList.onCreated(function () {
.
.
.
[중략]
.
.
.
window.postCnt = new ReactiveVar(20);
var self = this;
var subs = new SubsManager(); // 추가 내용
.
.
.
[중략]
.
.
.
self.autorun(function () {
subs.subscribe('posts', postCnt.get()); // self를 subs로 변경
});

자 이제 결과를 볼텐데요. 현재 subscriptions(구독) 되고 있는 내용을 보기 위해서 패키에 msavin:mongol 를 설치해서 구독 내용을 살펴보도록 하겠습니다. 참고로 msavin:mongol 패키지는 meteor디버그 툴로서 현재 화면에서 pub/sub 이 정상적으로 일어나고 있는지 collection을 모니터링 할 수 있는 툴입니다. 검색해보시면 이 툴에 대한 자세한 내용들을 쉽게 알 수 있을 것 입니다. 사용법은 브라우저에서 윈도우는 ctrl + m 맥은 control + m 를 입력하면 됩니다.

자 이제 다시 실행해 보겠습니다. 보시는 바와 같이 내용을 본 후 뒤로 가기를 해도 기존의 구독된 subscriptions이 초기화 되지 않는 것을 볼 수 있습니다 .

[subs-manager 적용 화면]

다음으로 해결해야할 문제는 스크롤의 위치를 기억하는 것입니다. 이 문제 역시도 해결해줄 패키지가 있는데 tomwasd:flow-router-autoscroll 라는 패키지가 되겠습니다. 다음을 참고로 패키지만 설치하면 작동합니다.

meteor add tomwasd:flow-router-autoscroll

설치 후 실행을 시켜보면 다음과 같이 뒤로가기로 돌아와도 이전의 위치로 스크롤이 돌아온 것을 볼 수 있습니다.

[subs-manager 적용 화면]

하지만 여기서 끝은 아닙니다. 아직 문제가 완전히 해결되지 않았는데요. 바로 postCnt문제 입니다. 현재 캐쉬를 이용해 subscriptions(구독) 된 내용은 캐시되고 있지만, 문제는 이 상태에서 다시 다음페이지를 불러보면 postCnt 가 초기화 되어 있어 postCnt가 처음 로딩되는 20부터 ~ 다음페이지 까지 순차적으로 다시 로딩을 하는 심각한 문제가 있습니다.

이부분을 해결하기 위채 처음 생각한 방법은 페이지가 변경되면 url에 현재 post개수를 넣어준 다음 그것을 받아서 사용하면 되지 않을까 하고 생각했습니다. 하지만 이렇게 되면 페이지가 넘어갈 때마다 url이 변경되어 authscroll에 의해 계속해서 맨 위 페이지로 가버리는 현상이 발생했습니다. 그래서 이 방법은 아니란 결론이 들어 고민하다 발견한 해결방법은 autoscroll 패키지를 수정해서 사용하는 방법이 좋겠다는 결론을 내렸습니다. 실제로 autoscroll 패키지의 구조는 매우 단순한 형태입니다.
그럼 이제부터 어떻게 autoscroll을 수정할 지 알아보도록 하겠습니다. 우선 autoscroll을 이패키지를 삭제해 주세요.

meteor remove tomwasd:flow-router-autoscroll

그후에 다음 소스를 autoscroll.js 에 입력해주세요. 아래 소스는 조금 전 삭제한 low-router-autoscroll 내용이 되겠습니다. 이 소스의 핵심적인 기능은 saveScrollPosition, scrollToTop 두가지 함수가 되겠습니다. saveScrollPosition은 스크롤의 위치 ($(window).scrollTop();)를 저장하는 함수이고 scrollToTop는 리스트 페이지로 돌아왔을 때 저당된 스크롤의 위치로 보내주는 역할을 하는 함수입니다. 그리고 이 둘은 Flowrouter에서 제공되는 기능을 통해 필요한 때에 작동을 합니다. FlowRouter.triggers.exit는 페이지를 나갈 때 그리고 FlowRouter.triggers.enter 는 페이지로 들어올 때 각각 함수들을 실행시켜 주는 역할을 한다고 생각하시면 되겠습니다.

client/autoscroll.js

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
42
43
44
45
46
47
(function () {
FlowRouterAutoscroll = {
animationDuration: 200,
};
var scrollPositions = {};
var backToPosition;
// Keep track of the last position for every page in case we return to it
// via the back button or history.
var saveScrollPosition = function () {
scrollPositions[window.location] = $(window).scrollTop();
};
window.onpopstate = function(event) {
// We used the back button, find the position we were at on that page
// last time
backToPosition = scrollPositions[window.location];
};
// Scroll to the right place after changing routes. "The right place" is:
// 1. The previous position if we're returning via the back button
// 2. The top of page otherwise
var scrollToTop = function () {
// defer until after the DOM update so that the position can be correct
Tracker.afterFlush(function () {
var position;
if (backToPosition) {
position = backToPosition;
backToPosition = null;
}
else {
position = 0;
}
$('body,html').animate({
scrollTop: position
}, FlowRouterAutoscroll.animationDuration);
});
};
FlowRouter.triggers.exit([saveScrollPosition]);
FlowRouter.triggers.enter([scrollToTop]);
}).call(this);

이제 위의 소스를 다음과 같이 변경해 보겠습니다. 우선 postCnt에 대한 ReactiveVar 선언을 autoscroll.js에서 해줍니다. 그리고 post-lists.js 에 있는 window.postCnt = new ReactiveVar(20); 이부분은 삭제해 주겠습니다. 페이지를 나갈 때 FlowRouter.triggers.exit([saveScrollPosition]); 에 기존에는 스크롤의 위치만 저장하는 형태이지만 이제 postCnt도 함께 저장하도록 소스를 변경했습니다. 이제 saveScrollPosition 함수를 호출하면 scrollPosion과 postCnt(로드될 포스트 수) 두가지가 저장되게 됩니다. 마찬가지로 scrollToTop 함수가 실행될 때는 스크롤 위치를 불러 이동시켜 주는 것과 동시에 postCnt(로드될 포스트 수) 도 그대로 세팅되게 됩니다. 아래를 참고로 이전 소스를 수정해 주세요.

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
42
43
44
45
46
47
48
49
50
51
52
53
(function () {
window.postCnt = new ReactiveVar();
var scrollPositions;
var backToPosition;
var postCntGet;
var backToPage;
var saveScrollPosition = function () {
scrollPositions = $(window).scrollTop();
postCntGet = postCnt.get();
};
window.onpopstate = function(event) {
backToPosition = scrollPositions;
backToPage = postCntGet;
};
var scrollToTop = function () {
Tracker.afterFlush(function () {
var position;
if (backToPosition) {
position = backToPosition;
backToPosition = null;
}
else {
position = 0;
}
if(postCntGet)
{
postCnt.set(postCntGet);
}
else {
postCnt.set(20);
}
$('body,html').animate({
scrollTop: position
}, 1);
});
};
FlowRouter.triggers.exit([saveScrollPosition]);
FlowRouter.triggers.enter([scrollToTop]);
}).call(this);

자 이제 결과를 실행해 보겠습니다. 그러면 다음과 같이 스크롤을 이용해 페이지를 내리다, 내용을 보고 다시 돌아와도 이전까지의 데이터는 물론 스크롤 위치도 기억해 이동시켜 준 것을 볼 수 있을 것입니다.

[최종 결과물]

참 별거 아닌것 같은 기능이지만, 이 기능에 대한 구현 정보가 많지 않은 것도 사실일 것입니다. (혹은 제가 검색을 지지리도 못하거나 ㅠㅠ) 혹시 이부분에 대해서 고민하는 분이 있으시다면 조금이나마 도움이 되시면 좋겠네요.

다음 강좌는 언제라고 말씀드리긴 그렇지만, 그때는 조금더 기본부터 실용예제까지 차근차근 작성해볼까 생각중에 있습니다. 아마도 blaze가 아닌 vue를 사용힐 할 것 같기도 합니다.

그럼 다음에 또 만나요 ^^

소스코드 링크
https://github.com/freeseamew/meteor-infinit-scroll