7/26 TIL (렌더링 방식 복습, 애니메이션 코드 변경)

Hwi·2024년 7월 26일

TIL

목록 보기
79/96

📖 렌더링 방식

클라이언트 사이드 렌더링 (CSR)

개념

  • 모든 렌더링 작업이 클라이언트(브라우저)에서 수행됩니다.
  • 서버는 초기 HTML 파일만 전달하고, 나머지 콘텐츠는 클라이언트가 js를 통해 동적으로 가져와 렌더링합니다.

장점

  • 초기 페이지 로딩 후 빠른 페이지 전환이 가능해 사용자 경험이 향상됩니다.

  • 서버 부하가 줄어듭니다.

단점

  • 검색 엔진 최적화(SEO)에 불리할 수 있습니다.

  • 초기 페이지 로딩 속도가 느릴 수 있습니다.

예시 코드

import React, { useEffect, useState } from 'react';

const App = () => {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetch('/api/data')
      .then(response => response.json())
      .then(data => setData(data));
  }, []);

  return (
    <div>
      {data ? <div>{data.message}</div> : <div>Loading...</div>}
    </div>
  );
};

export default App;

서버 사이드 렌더링 (SSR)

개념

  • 모든 렌더링 작업이 서버에서 수행됩니다.
  • 서버는 클라이언트에게 완전히 렌더링 된 HTML 파일을 전달합니다.

장점

  • 초기 페이지 로딩 속도가 빠릅니다.
  • SEO에 유리합니다.

단점

  • 서버 부하가 증가할 수 있습니다.
  • 페이지 전환 시마다 서버 요청이 필요하여 사용자 경험이 떨어질 수 있습니다.

예시 코드

import React from 'react';

const App = ({ data }) => (
  <div>
    {data ? <div>{data.message}</div> : <div>Loading...</div>}
  </div>
);

export async function getServerSideProps() {
  const response = await fetch('https://api.example.com/data');
  const data = await response.json();

  return { props: { data } };
}

export default App;

스태틱 사이트 생성 (SSG)

주요 특징

  • 빌드 타임 렌더링: 빌드 과정에서 모든 페이지가 미리 렌더링되어 정적인 HTML 파일로 생성됩니다.

  • 빠른 로딩 속도: 사용자가 페이지를 요청할 때 이미 완전히 렌더링된 HTML 파일을 제공하므로 매우 빠르게 로딩됩니다.

  • SEO에 유리: 검색 엔진 크롤러는 완전히 렌더링된 HTML 페이지를 바로 크롤링할 수 있어 SEO에 유리합니다.

  • 변경 시 재배포 필요: 콘텐츠 변경이 있을 경우, 웹사이트를 다시 빌드하고 배포해야 합니다.

장점

  • 성능: 미리 렌더링된 HTML 파일을 제공하므로 초기 로딩 속도가 매우 빠릅니다.
  • SEO: SSR처럼 검색 엔진 최적화에 유리합니다.
  • 보안: 서버에서 동적으로 데이터를 가져오지 않으므로 잠재적인 보안 취약점이 줄어듭니다.

단점

  • 유연성 부족: 자주 변하는 데이터나 사용자별로 달라지는 콘텐츠를 처리하기 어렵습니다.
  • 재빌드 필요: 콘텐츠 변경 시 전체 사이트를 다시 빌드하고 배포해야 합니다.

예시 코드

// pages/index.js
import React from 'react';

export default function Home({ posts }) {
  return (
    <div>
      <h1>Blog Posts</h1>
      <ul>
        {posts.map((post) => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  );
}

// getStaticProps 함수는 빌드 타임에 데이터를 가져와서 페이지에 전달합니다.
export async function getStaticProps() {
  const res = await fetch('https://jsonplaceholder.typicode.com/posts');
  const posts = await res.json();

  return {
    props: {
      posts,
    },
  };
}

정리

특징CSRSSRSSG
초기 로딩 속도느림 (초기 JavaScript 로드 필요)빠름 (완전히 렌더링된 HTML 제공)매우 빠름 (정적 HTML 제공)
페이지 전환 속도빠름 (클라이언트 측에서 JavaScript로 처리)느림 (서버 요청 필요)빠름 (정적 HTML 제공)
SEOSEO에 불리할 수 있음SEO에 유리SEO에 유리
서버 부하낮음높음매우 낮음
개발 복잡도클라이언트 측 로직에 집중 (단순할 수 있음)서버와 클라이언트 모두 다룸 (복잡할 수 있음)데이터 변경 시 재빌드 필요 (유연성 부족)

📖 애니메이션 코드 변경

디자이너 분이 기획한 건 전체 행성 중 3개를 먼저 보여주고, 슬라이더 시에 나머지 행성들을 순차적으로 로테이션 도는 방식인데

제가 구현한 건 아예 처음부터 화면에 6가지의 행성이 전부 보여지는 것이기에 기획했던 거랑 다르게 흘러가는 것 같아서 코드를 일부 수정했습니다.

기존 행성 애니메이션 코드

// 기존 코드에서의 행성 애니메이션
useEffect(() => {
  const animatePlanets = () => {
    const radius = 500; // 고리 반경
    const angleStep = (2 * Math.PI) / planets.length; // 각 행성 사이의 각도

    planetsRef.current.forEach((planet, index) => {
      if (planet) {
        const angle = (index - 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;
        const scale = isVisible ? 1.5 : 1;
        const zIndex = isVisible ? 10 : 0;
        const opacity = isVisible ? 1 : 0.5;

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

  if (videoLoaded) {
    animatePlanets();
  }
}, [currentSlide, videoLoaded]);

수정 후 애니메이션 코드

// 새로운 코드에서의 행성 애니메이션
useEffect(() => {
  const animatePlanets = () => {
    const radius = 500; // 고리 반경
    const angleStep = (2 * Math.PI) / planets.length; // 각 행성 사이의 각도

    planetsRef.current.forEach((planet, index) => {
      if (planet) {
        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) || (index < currentSlide && index + planets.length < currentSlide + visiblePlanetsCount);
        const isActive = adjustedIndex === (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(planet, {
          x: xPos,
          y: yPos,
          z: zPos,
          scale: scale,
          zIndex: zIndex,
          opacity: opacity,
          duration: 1,
          ease: 'power2.inOut',
        });
      }
    });
  };

  if (videoLoaded) {
    animatePlanets();
  }
}, [currentSlide, videoLoaded]);

기존의 코드와 다른 점을 설명해보겠습니다.

1. adjustedIndex 변수

  • 행성의 위치를 조정하여 선택된 행성이 가운데에 위치할 수 있도록 작성한 코드

2. isActive 변수

  • 현재 슬라이드에서 가운데에 있는 행성을 선택한 후, isActive = true;인 경우에 행성의 크기(scale)을 키우고, z-index를 높여 입체감을 강조합니다.

3. 로직 가시성 상승

  • isVisible 변수는 슬라이드 범위 내에 있는 행성인지 확인하고, index < currentSlide일 경우에도 행성을 가시성 범위 내에 포함시킵니다.

4. 그 외 스타일 조정

  • zIndex와 opacity 값 조정을 함으로써 기존보다 더 입체감을 살릴 수 있었습니다.

현재 결과물

저기서 슬라이더를 할 시 행성이 순서대로 로테이션 되는 형식입니다.

profile
개발자가 되고 싶어~~~

4개의 댓글

comment-user-thumbnail
2024년 7월 26일

대박이잖아... 휘진님 프로젝트 넘 기대돼요 ㅠ

1개의 답글