Scroll 에 따른 fixed 구현하기

Eddy·2022년 11월 5일
1

React

목록 보기
10/21

Kream 클론코딩 중 구현해야 했던 Scroll에 따른 fixed

왼쪽의 캐러셀이 빨간박스에 닿으면 멈춰보이게 해야한다.
(이해를 돕기위해 Kream서비스에 border를 넣었다.)


현재 상황

현재 fixed인 초록 박스를 삼항연산자로 조건부 스타일링을 해주면 된다.
그러기 위해선 스크롤값을 구하고 일정 스크롤 값에 도달하면 useState hook 을 이용하여 false->true로 상태를 변경한다.
false 일 땐 position:fixed; true 일 땐 position: absolute; 를 주겠다고 계획했다.

1. 스크롤 값을 구하고 useState 를 이용해 저장해준다.

const [scrollY, setScrollY] = useState(0);
const [scrollActive, setScrollActive] = useState(false);

const scrollFixed = () => {
  if (scrollY > 1350) {
    setScrollY(window.pageYOffset);
    setScrollActive(true);
  } else {
    setScrollY(window.pageYOffset);
    setScrollActive(false);
  }
};

window.pageYOffset을 사용해서 스크롤 Y의 값을 저장한다.
그리고 console.log(scrollY) 를 이용해 scrollY가 어느 값에 도달 했을때 조건부 스타일링을 위한 setScrollActive(true) 를 해줄지 찾아내고 if조건문을 사용해준다.

2. 스크롤 실시간 감시

useEffect(() => {
 function scrollListener() {  
   window.addEventListener("scroll", scrollFixed); } 
  //  window 에서 스크롤을 감시 시작
   scrollListener(); // window 에서 스크롤을 감시
      return () => {
     	window.removeEventListener("scroll", scrollFixed); }; 
  //  window 에서 스크롤을 감시를 종료
  });

useEffect 로 실시간 감시를 해줘야한다, 즉 스크롤이 시작되면 위에 작성한 scrollFixed() 함수를 실행해준다.
주의할 점은 반드시 이벤트리스너를 삭제해 줘야 스크롤할때 2-3번씩 렌더 되지 않는다.

3. 삼항연산자를 이용한 조건부 스타일링.

 <Box style={{
      position : scrollActive ? 'absolute' : 'fixed',
      top : scrollActive ?  null : '130px' ,
      bottom : scrollActive ? '0' : null }} >

인라인스타일을 지양하기 위해 추후 props를 이용해 리펙토링예정.


트러블슈팅

const scrollFixed = () => {
  if (scrollY > 1350) {//생략}

문제가 있다. 단순히 스크롤값만 이용해 조건을 해주다 보니 오른쪽 모달들을 열었을 때 스크롤 값(길이)이 달라지며 빨간 박스에 다다르기도 전에 스타일이 변한다.
어떤 방법을 써야 매번 변하는 스크롤 값에 맞춰 빨간 박스에 도달했을때 초록색 박스가 붙는 것 처럼 보이도록 할수 있을까 많은 고민을 했다.
그러다 useRef를 이용해 변하는 빨간 박스의 높이값을 구해서 구현해보기로 했다.

const containersRef = useRef(null);
const boxRef = useRef(null);

  const scrollFixed = () => {
    if (scrollY > containersRef.current?.offsetHeight - boxRef.current?.offsetHeight ) {
      setScrollY(window.pageYOffset);
      setScrollActive(true);
    } else {
      setScrollY(window.pageYOffset);
      setScrollActive(false);
    }
  };

<Fixed ref={containersRef}>
    <Box ref={boxRef} style={{
      position : scrollActive ? 'absolute' : 'fixed',
      top : scrollActive ?  null : '130px' ,
      bottom : scrollActive ? '0' : null }} >
</Fixed>

완성된 결과물

스크롤중 모달이 열려 스크롤의 길이가 달라져도 정상적으로 보인다.
반응형으로 초록색 박스의 높이가 바뀌어도 빨간 박스의 끝에 닿았을때 변한다.
if (scrollY > containersRef.current?.offsetHeight - boxRef.current?.offsetHeight )

코드 전문

0개의 댓글