WEB/REACT

[REACT] 리액트 컴포넌트에 scroll이벤트 사용하기/ debounce와 throttle

자바칩 프라푸치노 2021. 8. 23. 21:41

문제발생

우리의 서비스에는 피드가 있다.

이 피드를 계속 구경하다가 다른 페이지를 갔다가 다시 오면 내가 보던 그 화면으로 갔으면 좋겠다.

 

 

 

 

 

처리

먼저 리액트 컴포넌트에다가 scroll이벤트를 주어야한다.

우리는 window자체가 스크롤이 되는 형태가 아니기에 div자체에 scroll이벤트를 주어야한다.

그러면 onscroll을 쓰면된다.

 

나는 최상위 컴포넌트 (styled componen)를 ref contain을 주었고

onscroll로 scroll이라는 함수를 넣어주었다.

  //scroll 이벤트 관련
  const [scrollLocation, setScrollLocation] = useState(0);
  const lastScroll = useSelector(state=> state.review.current_scroll);
  const scroll = (e)=>{
    setScrollLocation(e.target.scrollTop)
  //1번위치
    // dispatch(reviewActions.saveCurrentScroll(scrollLocation))
  }

  
  const contain = useRef(null);
  useEffect(()=>{
    contain.current.scrollTo(0, lastScroll);
    return ()=>{
      //2번위치
      dispatch(reviewActions.saveCurrentScroll(scrollLocation))
    }
  },[])

 

 

 

 

여기서 문제 발생

나는 여기서 useState로 scroll의 위치를 기억하여 리덕스에 저장하고 싶다.

unmount되기 직전에 저장하고 싶은데 return문에 넣으니 unmount되고 나서 실행이 되는 것이다.

그렇다고 지금 deps에 넣을 마땅한 값이 생각나지 않았다.

scroll위치를 넣어버리면 무한 렌더링이 되기 때문이다.

 

그렇다고 scroll이벤트가 발생할때마다 리덕스에 저장하면 액션이 너무 많이 생겨서 부하가 생길 것 같았다. .

하지만 useState로 값을 업데이트 하거나 액션을 실행하거나 둘다 문제였다.

 

 

 

 

 

 

해결

debounce와 throttle을 생각해냈다.

debounce는 아무리 많은 이벤트가 일어나도 다 무시하고 일정 시간동안 이벤트가 일어나지 않으면 그때서야 함수가 실행되는 것이다.

throttle을 일정 주기마다 함수가 계속 실행되는 것이다.

나는 우리의 프로젝트에 debounce가 적합하다고 생각했다.

사람들이 피드를 내리면서 글을 읽고, 다른페이지로 이동한다고 생각했기 때문이다.

 

라이브러리를 사용해도 되지만 간단해서 직접 구현했다.

 setTimeout 은 일정시간이 지난 후에 함수가 실행되도록 처리하는 역할을 하며,

   clearTimeout 은 setTimeout을 취소하는 역할을 한다.
[변수] = setTimeout([함수명], [함수가 실행될 시간]);

   clearTimeout([변수]);

​
//scroll 이벤트 관련
  const lastScroll = useSelector(state=> state.review.current_scroll);
  var timer;
  const scroll = (e)=>{
    if (timer) {
      clearTimeout(timer);
    }
    timer = setTimeout(function() {
      dispatch(reviewActions.saveCurrentScroll(e.target.scrollTop))
    }, 500);
  
  }

  const container = useRef(null);
  useEffect(()=>{
    container.current.scrollTo(0, lastScroll);

  },[])

스크롤이 500ms 동안 멈춰있으면 timer가 실행되고 스크롤이 시작되면 timer가 사라지는 형식이다.

 

 

 

 

결과

 

 

728x90