react-intersection-observer useInview를 이용해 svg를 이용한 애니메이션 페이지를 만들어보자

슬로그·2024년 1월 29일

nextjs

목록 보기
4/4
post-thumbnail

1. react-intersection-observer 에 대해 알아보기 👊

1-1) react-intersection-observer ?

React 에서 intersection Observer API를 사용해 요소가 화면에 나타나는지 여부를 감지하는데 사용되는 라이브러리

설치

	npm install react-intersection-observer

useInView 훅을 호출하면 배열형태의 반환값이 나온다.
첫번째 요소는 ref 이고 두번째요소는 View 인데 ref는 감지하고자 하는 요소에 적용하고
inView는 해당요소가 뷰포트에 보이는지 여부를 나타낸다.

예시코드

import React from 'react';
import { useInView } from 'react-intersection-observer';

const MyComponent = () => {
  const [ref, inView] = useInView({
    triggerOnce: true, // 한 번만 트리거 옵션
  });

  return (
    <div ref={ref}>
      {inView ? 'Visible' : 'Not Visible'}
    </div>
  );
};

export default MyComponent;

1-2) 왜 Intersection Observer를 사용할까?

  1. useInviewintersection Observer를 기반 으로 하며 요소가 화면에 나타날 떄 특정 동작을 수행 할수 있는 기능을 제공한다.
  2. inView 변수를 통해 해당 요소가 화면에 보일때만 애니메이션 효과를 활성화 하는 등의 동적인 효과를 줄수 있다.
  3. 성능최적화
    • intersection Observer를 사용하면 화면에 보이는지 여부를 효율적으로 감지할 수 있다.
    • 예를 들어 특정 컴포넌트의 렌더링이나 리소스 로딩을 미루고 사용자가 해당 컴포넌트를 실제로 볼 때에만 이를 처리하고자 할때 'useInView'를 사용할 수있다.
    • triggerOnce: true 옵션을 사용하면 한 번만 트리거되어 불필요한 리렌더링을 방지할 수 있다.
  4. 애니메이션 타이밍 조절
    • delay 옵션으로 클래스에 대한 애미네이션 효과를 줄수 있다.
  5. User Experience 향상
    • 초기 로딩시에 필요한 자원을 최적화 해 불필요한 자원 로딩을 방지하고 페이지 성능을 향상시킬수 있다.
    • 사용자가 뷰포트에 스크롤 하거나 해당 영역을 볼때까지 자원을 로딩하지 않고 필요한 순간에만 로딩해 사용자 경험을 개선시킬수 있다.

2. react-intersection-observer 를 이용해 애니메이션 페이지를 만들어보자 👊

내 프로젝트의 condition은 next app router 를 기반으로 설정 되어있다.

react-intersection-observer 설치하고 useInView를 적용하고 보면 not defined 에러가 발생한다. 아마 클라이언트로 보여지는 부분이기 때문에 에러가 발생한것 같다.
next app router에서는 client 컴포넌트로 인식되기때문에 해결방법으로 'use client' 를 상단에 적용시켜줘야 한다. 그럼 에러가 해결된다. !

✨구현하기위한 목표

react-intersection-observer를 이용해 구현할 것은 inView가 활성화 됨에 따라 화살표를 svg를 애니메이션화 해주고 그에 따른 페이지 이동 을 구현하려고 한다. 😀

구현 방법 1. 📝 컴포넌트 만들기

제일 큰 부모 컴포넌트는 Portfolio.tsx 다.
하위 컴포넌트로 먼저 Intro.tsx 만들고 AnchorLink.tsx 파일을 생성해준다.

참고블로그

Postfolio.tsx

import Article from "@/components/Portfolio/Article";
import Intro from "@/components/Portfolio/Intro";
import AnchorLink from "@/service/AnchorLink";

export default function Portfolio() {
     
     return(
        <div>
         <Intro/>
         <Article/>
        </div>
     )
}

Intro.tsx는 말그대로 intro 컴포넌트이고 그안에 text클릭시 Link이동화살표애니메이션을 구현하는 곳은 AnchorLink.tsx 컴포넌트이다.

구현 방법 2. 📝 svg 생성 및 useInView 활성화

react-intersection-observer useInView 훅에서 ref 와 inView를 가져온뒤 옵션을 추가해준다.

AnchorLink.tsx

'use client';

import Link from "next/link";
import { useEffect } from "react";
import { useInView } from "react-intersection-observer";

type Props = {
    text:string;
    href:string;
}
export default function AnchorLink({text,href,...props}:Props) {
     const {ref , inView} = useInView({
        triggerOnce:true,
        delay:500
     })
    return(
      <div ref={ref}>
         <Link href={href}>{text}</Link>
        <svg
          aria-hidden="true"
          focusable="false"
          width="23"
          height="24"
          viewBox="0 0 23 24"
          fill="none"
          xmlns="http://www.w3.org/2000/svg"
        >
          <path
          className="tail"
          d="M0.5 1.49999C6.83333 0.999993 19.2 4.59999 18 23"
          style={{ strokeDashoffset: inView ? 0 : '31.95920181274414' }}
          />
          <path 
          className={`point`} 
          d="M13.5 16.5L18 23L22.5 16.5" 
          style={{ strokeDashoffset: inView ? 0 : '15.81138801574707' }}
          />
        </svg>
	</div>
    )
}

inView를 콘솔에서 확인해보면 처음엔 false였다가 곧바로 true변경되는것을 알수있다. 이는 애니메이션을 페이지가 화면에 보일때만 애니메이션 효과가 활성화되어 동적으로 변경시켜줄 수 있다. ! 👍

tailwind에서 inView 상태에 따라 stroke-dash-offset을 달리해야하는데 구글링에서 적절한 방법을 찾지못해 일단 style로 동적인 상태값을 넣어줬다.
inView 가 true일경우 stroke-dash-offset 을 변경해줌으로애니메이션화 시켜줄수 있다.

Intro컴포넌트는 말그대로 처음 보여주는 페이지다.
안에 title 문구와 AnchorLink.tsx 을 넣어주고 내가 원하는 text문구와 prop로 클릭시 어떤 링크로 이동할지 넣어줘야한다.

Intro.tsx

import AnchorLink from "@/service/AnchorLink";
import Text from "../Text";
import Title from "../Title";

export default function Intro() {
     
     return(
        <div id="intro" className="h-screen">
            <Title className="whitespace-pre-wrap">{`안녕하세요.😀 \ntest 문구 입니다.`}</Title>
            <AnchorLink text="Read more" href="#article"/>
        </div>
     )
}

구현 방법 4. 📝 id 값으로 href 넣어주기

위에 코드에서 #article로 href를 설정했는데 , 일단 Article컴포넌트를 하나 만들어주고 id를 통해 이동할수있도록 id를 같은 article로 적용해준다.

'use client';
import { useEffect } from "react";
import { useInView } from "react-intersection-observer"
import Text from "../Text";

export default function Article() {
    const {ref, inView} = useInView({
        triggerOnce:true,
        delay:500,
        threshold:0.5
    })
    
 
    return(
        <div id="article" className="h-screen py-[100px]" ref={ref}>
            <Text className="articles-fade-in text-2xl">Articles 페이지 애니메이션 test</Text>
        </div>
     )
}

내가 원하는건 한곳에 밑으로 내려가듯이 이동하는걸 원했기때문에 전체 page에는 모든게 다 포함되어있어야한다.

import Article from "@/components/Portfolio/Article";
import Intro from "@/components/Portfolio/Intro";
import AnchorLink from "@/service/AnchorLink";

export default function Portfolio() {
     
     return(
        <div>
         <Intro/>
         <Article/>
        </div>
     )
}

이렇게 구상하면 처음 보이는 Intro 에서 inView가 활성화 됨에 따라 화살표 애니메이션이 동적으로 변경 되고 Read more을 클릭 시 article로 넘어가게 된다.

🙄 5. 더 추가하기

Intro에서 Article로 이동할때 딱딱 끈어지는 듯한 것보단 부드러운 동작을 원한다면
html css 부분에 scroll-behavior : smooth; 를 넣어주면 부드럽게 이동한다 !

✨ 완성

profile
빨리가는 유일한 방법은 제대로 가는것

0개의 댓글