React, 스크롤 하면 사라지는 Header 구현

Jihu Kim·2024년 8월 11일
0

React

목록 보기
4/4
post-thumbnail

Header에 디테일 추가하기

멋쟁이 사자처럼 2024년 12기 중앙해커톤에 참가하면서 만들었던 Header이다.

기존에 만들었었던 Header에서 디테일을 추가해보았다.
슬라이드를 하게되면 Header가 사라지도록 했고, 네비게이션바를 통해서 이동하는 페이지가 아니라면 Header의 텍스트가 바뀌고 뒤로가기 버튼이 생기도록 했다.
아래는 이를 구현한 Header.jsx 코드이다.

Header.jsx

import {
  faAngleLeft,
  faBell,
} from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import React, { useEffect, useState } from 'react';
import {
  matchPath,
  NavLink,
  useLocation,
  useNavigate,
  useParams,
} from 'react-router-dom';
import './Header.scss';

export default function Header() {
  const [isVisible, setIsVisible] = useState(true);
  const [lastScrollY, setLastScrollY] = useState(0);
  const [isClicked, setIsClicked] = useState(false);

  const navigate = useNavigate();
  const location = useLocation();
  const { nickname } = useParams();

  const goBack = () => {
    navigate(-1);
  };

  const isNotificationPath = matchPath(
    '/app/notification',
    location.pathname
  );
  const isSmilePath = matchPath(
    '/profile/smile/:nickname',
    location.pathname
  );
  const isEditProfilePath = matchPath(
    '/profile/edit',
    location.pathname
  );
  const isAchievementPath = matchPath(
    '/profile/achievement/:nickname',
    location.pathname
  );

  const [scrollY, setScrollY] = useState(false);

  const handleScroll = () => {
    // 스크롤이 Top에서 50px 이상 내려오면 true값을 useState에 넣어줌
    if (window.scrollY >= 50) {
      setScrollY(true);
      // console.log(scrollY);
    } else {
      // 스크롤이 50px 미만일경우 false를 넣어줌
      setScrollY(false);
    }
  };

  useEffect(() => {
    window.addEventListener('scroll', handleScroll);
    return () => {
      window.removeEventListener('scroll', handleScroll); //clean up
    };
  }, []);

  useEffect(() => {
    if (scrollY > lastScrollY) {
      setIsVisible(false);
    } else {
      setIsVisible(true);
    }
    setLastScrollY(scrollY);
  }, [scrollY]);

  return (
    <div
      className={`header ${
        isVisible ? 'visible' : 'hidden'
      }`}
    >
      {isNotificationPath ||
      isSmilePath ||
      isEditProfilePath ||
      isAchievementPath ? (
        <div className="icon-back">
          <NavLink
            to="#"
            className={({ isActive }) =>
              isActive ? 'nav-link active' : 'nav-link'
            }
            onClick={goBack}
            onMouseDown={() => setIsClicked(true)}
            onMouseUp={() => setIsClicked(false)}
            style={{
              color: isClicked
                ? 'mediumslateblue'
                : 'white',
            }}
          >
            <FontAwesomeIcon icon={faAngleLeft} />
            &nbsp;&nbsp;
            {isNotificationPath
              ? '알림'
              : isSmilePath
              ? `😆${nickname}님의 웃음`
              : isEditProfilePath
              ? '📝프로필 수정'
              : isAchievementPath
              ? `🏅${nickname}님의 챌린지 기록`
              : ''}
          </NavLink>
        </div>
      ) : (
        <div className="logo">😆SmileHub</div>
      )}
      <div className="icon-bell">
        <NavLink
          to="/app/notification"
          className={({ isActive }) =>
            isActive ? 'nav-link active' : 'nav-link'
          }
        >
          <FontAwesomeIcon icon={faBell} />
        </NavLink>
      </div>
    </div>
  );
}

스크롤 시에 Header 숨기기

전체 코드를 보면 const [isVisible, setIsVisible] = useState(true);라는 변수를 두었다. 그리고 이를 통해서 Header를 숨길지 말지를 결정하게 된다. 아래는 전체 코드 중 스크롤에 따라 isVisible 상태를 true로 할지 false로 할지를 설정하는 과정에 대한 코드이다.

const [scrollY, setScrollY] = useState(false);

  const handleScroll = () => {
    // 스크롤이 Top에서 50px 이상 내려오면 true값을 useState에 넣어줌
    if (window.scrollY >= 50) {
      setScrollY(true);
      // console.log(scrollY);
    } else {
      // 스크롤이 50px 미만일경우 false를 넣어줌
      setScrollY(false);
    }
  };

  useEffect(() => {
    window.addEventListener('scroll', handleScroll);
    return () => {
      window.removeEventListener('scroll', handleScroll); //clean up
    };
  }, []);

  useEffect(() => {
    if (scrollY > lastScrollY) {
      setIsVisible(false);
    } else {
      setIsVisible(true);
    }
    setLastScrollY(scrollY);
  }, [scrollY]);

scss파일

scss파일은 css의 확장된 형태이다. css의 모든 문법을 지원하면서도 추가적인 기능을 제공하여 더 효율적이고 유지보수하기 쉬운 스타일시트를 작성할 수 있도록 돕는다. 기존 css에서 더 구조적으로? 설계할 수 있었다. 나도 이번 해커톤을 진행하면서 알게되었다.

@import '../../App.scss';

.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 6vh;
  z-index: 100;
  // background-color: #fff;
  //그라데이션 효과 주기
  background-image: linear-gradient(
    to right bottom,
    #ff5c5c,
    #ad6dfc
  );
  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
  min-width: 100vw;
  max-width: $max-width;
  margin-left: auto;
  margin-right: auto;
  transition: top 0.3s;

  &.hidden {
    top: -6vh;
  }

  &.visible {
    top: 0;
  }

  .logo {
    display: flex;
    align-items: center;
    font-size: 1.5rem;
    font-weight: bold;
    color: #eaeaea;
    padding-left: 1rem;
  }

  .icon-back {
    display: flex;
    align-items: center;
    padding-left: 1rem;
    font-size: 1.5rem;

    .nav-link {
      color: rgb(155, 155, 155);
      font-size: 20px;
      font-weight: bold;
    }

    // 선택되었을 때
    .active {
      color: #eaeaea;
    }
  }

  .icon-bell {
    display: flex;
    align-items: center;
    padding-right: 1rem;
    font-size: 1.5rem;

    .nav-link {
      color: rgb(255, 166, 0);
      font-size: 20px;
      font-weight: bold;
    }

    // 선택되었을 때
    .active {
      color: rgba(255, 255, 255, 0);
    }
  }
}

@media (min-width: $max-width) {
  .header {
    min-width: $max-width;
  }
}
profile
Jihukimme

0개의 댓글