Debounce 적용하기 (feat. Pinggu Project)

LNSol·2022년 11월 2일
0

Javascript

목록 보기
3/6

프로젝트에서 디바운스를 꼭 사용해야 할 일이 생겼다! 지난 수업 내용을 되짚어보며 프로젝트에 적용해보자👍

Debounce

디바운스는 어떤 이벤트가 지속적으로 발생하다가 이벤트가 종료 되었을 때 딱 한 번 그 이벤트에 대한 처리를 하도록 할 때 사용한다. 아주 간단한 예제를 보면 다음과 같다. 클릭을 연속적으로 계속 했지만 포스트를 달라는 요청은 두 번 출력되었다.

const debounce = (cb, delay ) => {
	let tm;
	return () => {
		console.log('clicked!!!');

		if (tm) clearTimeout(tm);
		tm = setTimeout(cb, dealy);
	}
};
const getPosts = () => console.log('포스트 주세요 요청~~!!!');
const act = debounce(getPosts, 500);

return <button onClick={act}>click</button/>;

이제 딱 보면 클로저란걸 안다ㅎㅎ 아무튼 act가 실행될 때마다 timeout을 clear해주고 다시 셋팅해주는 것을 확인할 수 있다. 일정 delay 시간이 지나지 않은 상태에서 다시 act를 호출하면 콜백으로 넘겨준 함수가 백그라운드에서 대기하고 있다가 clear될 것이다. 그리고 클릭을 멈추면 delay 시간이 지난 후에 백그라운드에서 태스크 큐로 넘어갈 것이고, 콜 스택이 비었을 때 실행되는 것이다!


나는 여기서 getPosts는 어떤 이벤트가 종료된 후에 한 번 실행되어야 할 함수이고, act는 여러 번 호출될 가능성이 있는 함수라고 이해하고 있다.



프로젝트에 적용하기

debounce 적용 전


지도가 움직이면 지도 범위 내에 등록되어 있는 포스트를 조회해서 노란색 마크로 뿌려준다. 처음에는 지도의 ‘dragend’ 이벤트에 포스트 조회 요청을 하는 함수를 걸어서 지도 이동이 완료되면 등록된 포스트를 가져오도록 했었다. 하지만 사용자가 직접 지도를 드래그 했을 때 뿐만 아니라 타임라인에서 특정 포스트를 클릭했을 때 지도의 중심 좌표가 포스트의 위치로 이동하는데, 그 때도 마찬가지로 범위 내 포스트들을 가져와야 한다.

그래서 ‘dragend’ 이벤트가 아니라 중심 좌표 변경 이벤트라는 ‘center_changed’이벤트에 걸어야 겠다고 생각했다. 그런데 이 ‘center_changed’이벤트는 이벤트가 수도 없이 발생한다.

지도를 1mm도 안 움직인 것 같은데 콘솔에 스크롤리 저렇게나 내려가있다. 디바운스를 사용하지 않고서는 이 이벤트에 포스트를 요청하는 함수를 걸 수가 없다!!



debounce 적용하기

// contexts/MapContext.tsx

...
const debounce = (cb, delay) => {
	let timer: any;
	return (map: kakao.maps.Map | null) => {
		if (timer) clearTimeout(timer);
		timer = setTimeout(cb, delay, map);
	}
};

/**
 * 지도 중심 좌표 변경 이벤트가 끝나고 한 번 실행되어야 할 함수
 * 지도의 범위를 구해서 서버로 요청을 보냄
*/
const getSubPosts = (map: kakao.maps.Map | null) => {
	const bounds = map?.getBounds();
  const [swLat, swLng] = bounds?.getSouthWest().toString().slice(1, -1).split(',') ?? [];
  const [neLat, neLng] = bounds?.getNorthEast().toString().slice(1, -1).split(',') ?? [];

  fetcher(`/posts/bounds?swLat=${swLat}&swLng=${swLng.trim()}&neLat=${neLat}&neLng=${neLng.trim()}&tab=home`)
    .then((posts) => {
      console.log(posts);
      const imageSrc = 'https://t1.daumcdn.net/localimg/localimages/07/mapapidoc/markerStar.png';
      const imageSize = new kakao.maps.Size(20, 32);
      const markerImage = new kakao.maps.MarkerImage(imageSrc, imageSize);
      posts.forEach((post: IPost) => {
        const position = new kakao.maps.LatLng(Number(post.latitude), Number(post.longitude));
        const subMarker = new kakao.maps.Marker({
          map,
          position,
          image: markerImage,
        });
        // event - 주변 포스트 마커 hover 시 인포윈도우 띄우기
        subMarker.addListener('mouseover', () => getSubPostInfo(subMarker, map, post, position));         // event - 주변 포스트 마커 클릭 시 포스트 상세 페이지로 이동
        subMarker.addListener('click', () => navigate(`/posts/${post.id}`));
      });
    })
    .catch((err) => console.error(err));
};

const act = debounce(getSubPosts, 500);

/* 지도 이벤트 등록 */
map.addListener('center_changed', () => act(map));


debounce 적용 후


마치 ‘dragend’ 이벤트에 등록한 것 처럼 동작한다! 하지만 특정 포스트를 클릭하거나 내 위치로 이동했을 때 역시 주변 포스트를 조회하고 마커를 뿌려주지.

0개의 댓글