스크롤을 내릴 때, 마치 엔딩 크레딧처럼 평면적으로 스크롤이 내려가는 것보다, 브라우저 영역에 들어가거나 나갈 때 transition이 일어나도록 수정하려 한다.

 

intersection-observer라는 브라우저 내장 기능을 통해 구현할 수 있다.

 

 

 

우선 테스트 뼈대를 잡았다.

참고로, 아래 Div와 Image 태그는 margin-top: 1000px; 값을 가져, 충분히 스크롤해야 나타나도록 설정해두었다.

import s from '../stores/styling'
import image from '../assets/images/artistregister-background.jpg'

export default function ScrollTest() {

  return (
    <>
        <s.Div className='test'>테스트</s.Div>
        <s.Image className='test' src={image} alt="photo"/>
    </>
  )
}

 

 

 

그리고 useRef를 사용해 DOM element에 직접 접근한다.

import { useRef } from 'react'
import s from '../stores/styling'
import image from '../assets/images/artistregister-background.jpg'

export default function ScrollTest() {
    const myref = useRef<HTMLDivElement>(null);
  return (
    <>
        <s.Div className='test' ref={myref}>테스트</s.Div>
        <s.Image className='test' src={image} alt="photo"/>
    </>
  )
}

 

 

 

 

useEffect 훅으로 IntersectionObserver을 설정한다. 이를 통해 특정 요소가 뷰포트에 들어오거나 나가는 것을 감지한다.

import { useRef, useEffect } from 'react'
import s from '../stores/styling'
import image from '../assets/images/artistregister-background.jpg'

export default function ScrollTest() {
    const myref = useRef<HTMLDivElement>(null);
    useEffect(() => {
        const observer = new IntersectionObserver((entries) => {    //entry: observed item의 리스트.
            const entry = entries[0];
            console.log('entry:', entry);
        })
        observer.observe(myref.current)
    }, [])
  return (
    <>
        <s.Div className='test' ref={myref}>테스트</s.Div>
        <s.Image className='test' src={image} alt="photo"/>
    </>
  )
}

 

 

 

그러나 위처럼 작성하면  Argument of type 'HTMLDivElement | null' is not assignable to parameter of type 'Element'. 에러가 나타난다. 

myref.current 이 null인지 확인하고, null이 아닐 때만 observe할 수 있게 처리한다.

 

import { useRef, useEffect } from 'react'
import s from '../stores/styling'
import image from '../assets/images/artistregister-background.jpg'

export default function ScrollTest() {
    const myref = useRef<HTMLDivElement>(null);
    useEffect(() => {
        const observer = new IntersectionObserver((entries) => {    //entry: observed item의 리스트.
            const entry = entries[0];
            console.log('entry:', entry);
        })
        if (myref.current) {
            observer.observe(myref.current)
        }
        return () => {
            if (myref.current) {
                observer.unobserve(myref.current)
            }
        }
    }, [])
  return (
    <>
        <s.Div className='test' ref={myref}>테스트</s.Div>
        <s.Image className='test' src={image} alt="photo"/>
    </>
  )
}

 

 


 

사실 여기에서 조금 의문이 들었다.

if 문을 처리할 때, myref.current 가 null 인 경우를 else 처리하면 되지 않나?

결론적으로는 안된다.

   if (myref.current) {
   	observer.observe(myref.current)
   }
   else {
   	oberserver.unobserve(myref.current)
   }

 

 if (myref.current === null) {
             observer.unobserve(myref.current)
 }
 else {
	observer.observe(myref.current)
 }

 

위 두 코드는 myref.current 가 null 인지 확인하는 것처럼 보이지만, 

첫번째 코드는 null일 때 else 문이 반드시 실행된다.

두번째 코드도 비슷하게 직접 null인지 확인하고 unobserve를 실행한다.

 

observer.unobserve는 관찰 중인 실제 DOM 요소가 있을 때만 호출되어야 하기 때문에, 위 두 코드는 잘못된 접근이다.

 


 

따라서 

import { useRef, useEffect } from 'react'
import s from '../stores/styling'
import image from '../assets/images/artistregister-background.jpg'

export default function ScrollTest() {
    const myref = useRef<HTMLDivElement>(null);
    useEffect(() => {
        const observer = new IntersectionObserver((entries) => {    //entry: observed item의 리스트.
            const entry = entries[0];
            console.log('entry:', entry);
        })
        if (myref.current) {	// myref.current 가 true 일때만 실행 = null이 아닌 경우 실행
            observer.observe(myref.current)
        }
        return () => {	// cleanup 함수
            if (myref.current) {
                observer.unobserve(myref.current)
            }
        }
    }, [])
  return (
    <>
        <s.Div className='test' ref={myref}>테스트</s.Div>
        <s.Image className='test' src={image} alt="photo"/>
    </>
  )
}

 

 

위처럼 작성하니, 콘솔에서도 뷰포트에 요소가 들어오면 true, 나가면 false를 반환하는 것을 확인할 수 있었다.

 

+ Recent posts