React JS 마스터클래스(NOMFLIX CLONE) - Header

짜스의 하루 ·2024년 6월 24일

먼저 Router 부터 설정한다.

사용자가 홈, TV 채널, 검색 페이지로 이동할 수 있는 단순한 네비게이션을 구현하고, Header를 통해 모든 페이지에서 공통적으로 보여지는 컴포넌트를 추가했다.

넷플릭스에 들어가게 되면, 제일 먼저 볼 수 있는 상단 즉 Header 부분을 만들어보자


정말 간단하게 styled-components를 사용하여 네비게이션 바를 만들어 보았는데, 이는 공통적으로 보이는 컴포넌트이고, 네비게이션 바는 브라우저 상단에 고정되어 있으며, 좌우로 나뉘어진 두 개의 열로 구성되어 있다.

Header에 애니메이션 입히기

첫번째 : Logo fillOpacity animation 주기
두번째 : 페이지 이동할 때마다, 빨간색 점 으로 이동한 지 알려주기!

첫번째 로고 --> animation 주기


NETFLEX 로고 (svg)의 path에 motion.path로 지정해두고,
로고에 마우스를 올렸을 때, 발생할 animation을 지정하면 된다!
--> varients 속성을 사용하면 된다


logoVarients는 Logo 컴포넌트의 애니메이션 변형(variants)들을 정의하는 객체이다.
두 가지 상태를 가지고 있으며, Logo 컴포넌트가 초기에는 nomal 상태에 있다가, 마우스를 올렸을 때(whileHover) active 상태로 전환된다.

이렇게 하면 마우스를 Logo 컴포넌트에 올렸을 때 로고의 투명도가 애니메이션을 통해 변경되며 반복적으로 변화하는 애니메이션을 확인할 수 있다!


두번째 페이지 이동 시 빨간 점 추가

여기서 생각해봐야할 점은,
만약 home으로 이동했을 때, 이동한 위치가 지정한 경로가 일치했을 때, 빨간색 점을 띄운다. 라고 생각했을 때, 그럼 이동한 위치가 지정한 경로가 일치한지 안한지는 어떻게 알지 ?

useMatch 를 사용하면 된다!

useMatch는 react-router-dom에서 제공하는 훅으로, 현재 URL이 특정 경로와 일치하는지를 검사하고, 일치할 경우 경로의 매칭 정보를 반환한다.

const homeMatch = useMatch('/');
const tvMatch = useMatch('/tv');

homeMatch에는 현재 URL이 "/"과 일치하면 그 정보가 객체 형태로, 일치하지 않으면 null이 들어가게 된다.
tvMatch도 마찬가지이다!


Link:

  • react-router-dom의 Link 컴포넌트는 클라이언트 사이드에서 경로를 변경하는 링크를 생성한다.
    to="/"to="/tv"는 각각 루트(Home)와 tv 경로로 연결된다.

homeMatch:

  • useMatch('/')로 정의된 homeMatch는 현재 URL이 '/'와 일치하는지를 확인한다.
    만약 현재 URL이 '/'라면 homeMatch는 true를 반환하고, 그렇지 않으면 null을 반환한다.

tvMatch:

  • useMatch('/tv')로 정의된 tvMatch는 현재 URL이 '/tv'와 일치하는지를 확인한다.
  • 만약 현재 URL이 '/tv'라면 tvMatch는 true를 반환하고, 그렇지 않으면 null을 반환한다.

이렇게 클릭했을 때, url일치한 지 확인한 후, 링크에 맞춰서 빨간색 버튼이 생성이 되는 것을 확인할 수 있다!


이제 Search를 수정해보자


돋보기 이미지를 누르면 input창이 등장하고, 돋보기 이미지도 함께 이동한다!
이후, 돋보기 이미지를 다시 누르면 닫히는 애니메이션을 추가해보자

 const [searchOpen, setSearchOpen] = useState(false);
  const toggleSearch = () => {
    setSearchOpen((prev) => !prev);
  };

useState(false)는 searchOpen 상태를 초기값 false로 설정하고, 이를 변경할 수 있는 setSearchOpen 함수를 제공한다.

toggleSearch 함수는 searchOpen 상태를 반전시킨다. 이 함수가 호출될 때마다 searchOpen은 false에서 true, true에서 false로 토글된다.

<motion.svg> :

  • motion.svg에 클릭 이벤트(onClick={toggleSearch})를 통해 toggleSearch 함수를 호출한다.
  • animate={{ x: searchOpen ? -180 : 0 }} : searchOpen 상태에 따라 아이콘의 x축 위치를 -180 픽셀로 이동하거나 원래 위치로 이동한다. 이로 인해 검색창이 열리거나 닫힐 때 아이콘이 이동한다.
  • transition={{ type: 'linear' }} : 애니메이션의 전환 유형을 선형으로 설정한다.

<Input>:

  • animate={{ scaleX: searchOpen ? 1 : 0 }} : searchOpen 상태에 따라 x축 방향으로 확대되거나 축소된다. scaleX: 1은 원래 크기를 의미하며, scaleX: 0은 축소된 크기를 의미한다.
  • transition={{ type: 'linear' }}: 애니메이션의 전환 유형을 선형으로 설정한다.

이로써 Input창과 motion.svg는 애니메이션을 작동하게 된다!


이왕 하는거 제목 S-FLEX로 변경해보기

구글 폰트로 Logo만들기 이 사이트에 들어가면 구글 폰트로 SVG만들 수 있다!

원하는 폰트 찾아서 복사하면 되는데!

대충 이런식으로 나온다!
똑같이 복사하고, 적용시키면 된다!

쿠쿠 S-FLEX멋있게 나온걸 알 수 있다.


useAnimation()

useAnimation()를 사용하면 시작 및 중지 메서드가 있는 AnimationControls을 만들 수 있다.

기존에

const toggleSearch = () => {
    setSearchOpen((prev) => !prev);
  };
<Input
      placeholder="Search for movie or tv show ..."
      animate={{ scaleX: searchOpen ? 1 : 0 }}
      transition={{ type: 'linear' }}
/>

이러한 코드를 useAnimation() 를 사용해서 변수로 animation을 만들 수 있다.

const inputAnimation = useAnimation();
  const toggleSearch = () => {
    if (searchOpen) {
      inputAnimation.start({
        scaleX: 0,
      });
    } else {
      inputAnimation.start({
        scaleX: 1,
      });
    }
    setSearchOpen((prev) => !prev);
  };
  • useAnimation 훅을 사용하여 inputAnimation이라는 애니메이션 컨트롤러를 생성
  • searchOpen이 true일 때: scaleX를 0으로 설정하여 입력란의 너비를 0으로 줄인다.
  • searchOpen이 false일 때: scaleX를 1로 설정하여 입력란의 너비를 원래 크기로 확장한다.

inputAnimation을 animate에 적어두고, initial 즉 초기 상태도 적어주어야 한다..

나는 아무래도 첫 번째 방법이 더 편한 것 같다 호호!!


스크롤하면 떠올라야 하는 것은 ? useScroll (useViewportScroll" 은 "useScroll" 로 변경)

useScroll로 y축의 값을 얻어온 다음, 그 범위로 배경색 변경이 되도록 애니메이션이 이루어져야 한다.

1 . navVariants 객체
navVariants는 두 가지 상태 (top, scroll)에 대한 배경색 스타일을 정의하는 객체

  • top: 네비게이션 바가 페이지 상단에 있을 때 투명한 배경색.
  • scroll: 페이지를 스크롤한 후 불투명한 검정색 배경색.

2 . useScroll 훅
const { scrollY } = useScroll();
: useScroll 훅은 페이지의 스크롤 위치를 추적

3 . useAnimation 훅
const navAnimation = useAnimation() ;
useAnimation 훅은 애니메이션 컨트롤러를 생성 --> start, end, stop등 다양하게 적용 가능

4 . useMotionValueEvent

  • useMotionValueEvent 훅은 scrollY 값이 변경될 때마다 콜백 함수를 실행한다.
  • 'change' 이벤트가 발생할 때마다 scrollY.get()을 사용하여 현재 스크롤 위치를 가져온다.
  • 스크롤 위치가 80을 초과하면 navAnimation 컨트롤러의 start 메서드를 호출하여 'scroll' 상태로 전환한다.
  • 그렇지 않으면 start 메서드를 호출하여 'top' 상태로 전환한다.
<Nav variants={navVariants} initial="top" animate={navAnimation}>
  • animate={navAnimation}: navAnimation 컨트롤러에 의해 애니메이션 상태가 제어된다.
  • variants={navVariants}: navVariants 객체에 정의된 상태(top, scroll)에 따라 스타일이 변경된다.
  • initial="top": 초기 애니메이션 상태를 'top'으로 설정한다.

그럼 이렇게 처음에는 투명한 배경색이였다가 스크롤을 하면 검정색으로 배경화면이 바뀌는 nav를 확인할 수 있다!

profile
2024. 01. 02 ~ 백앤드 공부 시작, 2024. 04.01 ~ 프론트 공부 시작

0개의 댓글