8/6 TIL

Hwi·2024년 8월 6일

TIL

목록 보기
86/96

메인페이지 page.tsx에 있는 useEffect 로직 커스텀훅으로 작성

useVideoLoaded.ts

import { useEffect, useRef, useState } from "react"

const useVideoLoaded = () => {
  const videoRef = useRef<HTMLVideoElement | null>(null);
  const [videoLoaded, setVideoLoaded] = useState<boolean>(false);
  
  useEffect(() => {
    if (videoRef.current) {
      const videoElement = videoRef.current;
      const checkVideoLoaded = () => {
        if (videoElement.readyState >= 3) {
          setVideoLoaded(true);
        }
      };
      checkVideoLoaded();
    }
  }, []);
  return { videoRef, videoLoaded }
}

export default useVideoLoaded

useSlideAnimation.ts

import { useEffect } from 'react';
import gsap from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';

gsap.registerPlugin(ScrollTrigger);

type Planet = {
  id: string;
  planet_img: string;
  price?: number;
};

const useSlideAnimation = (
  videoLoaded: boolean,
  planets: Planet[],
  currentSlide: number,
  visiblePlanetsCount: number,
  planetsRef: React.RefObject<(HTMLDivElement | null)[]>
) => {
  useEffect(() => {
    const animatePlanets = () => {
      const radius = 500; // 고리 반경
      const angleStep = (2 * Math.PI) / planets.length; // 각 행성 사이의 각도

      planetsRef.current?.forEach((planetElement, index) => {
        if (planetElement) {
          const adjustedIndex =
            (index + (planets.length - Math.floor(visiblePlanetsCount / 2))) %
            planets.length;
          const angle = (adjustedIndex - currentSlide) * angleStep; // 각 행성의 위치 계산
          const xPos = radius * Math.sin(angle); // x 좌표
          const yPos = 0; // y 좌표
          const zPos = radius * Math.cos(angle); // z 좌표
          const isVisible =
            (index >= currentSlide &&
              index < currentSlide + visiblePlanetsCount) || // visiblePlanetsCount 개수만큼 행성이 보이도록 조건식
            (index < currentSlide &&
              index + planets.length < currentSlide + visiblePlanetsCount);
          const isActive =
            index ===
            (currentSlide + Math.floor(visiblePlanetsCount / 2)) %
              planets.length;
          const scale = isActive ? 2 : 1;
          const zIndex = isActive ? 10 : 0;
          const opacity = isVisible ? (isActive ? 1 : 0.5) : 0;

          gsap.to(planetElement, {
            x: xPos,
            y: yPos,
            z: zPos,
            scale: scale,
            zIndex: zIndex,
            opacity: opacity,
            duration: 1,
            ease: 'power2.inOut',
          });

          // 디버깅을 위한 로그 추가
          const planet = planets[index]; // planets 배열의 요소 가져오기
          const tourPrice: number | undefined = planet.price;
          console.log(`Planet ${planet.id} - Price: ${tourPrice}`);
        }
      });
    };

    if (videoLoaded && planets.length > 0) {
      animatePlanets();
    }

    ScrollTrigger.refresh();
  }, [currentSlide, videoLoaded, planets]);
};

export default useSlideAnimation;

useScrollTrigger.ts

import { useEffect } from 'react';
import gsap from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';

gsap.registerPlugin(ScrollTrigger);

const useScrollTrigger = (
  videoLoaded: boolean,
  sectionRef: React.RefObject<HTMLDivElement>
) => {
  useEffect(() => {
    if (videoLoaded && sectionRef.current) {
      ScrollTrigger.create({
        trigger: sectionRef.current,
        start: 'top top',
        pin: true,
        pinSpacing: false,
        scrub: true,
      });

      ScrollTrigger.refresh();
    }
  }, [videoLoaded, sectionRef]);
};

export default useScrollTrigger;
profile
개발자가 되고 싶어~~~

0개의 댓글