반응형 헤더

On Netlify => Code

React에서 반응형 헤더를 만드는 것은 복잡할 것이라고 생각했는데 막상 구현해 보니 생각보다 훨씬 간단했습니다.

반응형 헤더를 만들 때 가장 먼저 생각해야 할 것은 크기가 조정될 때마다 화면을 측정하는 방식인 것 같습니다. 그리고 다행스럽게도 자바스크립트는 정확히 그 목적을 위한 eventListener, resize eventListener를 제공합니다.

반응형 헤더를 만드는 목표를 달성하기 위해 해당 eventListener를 어떻게 활용할 수 있는지 봅시다.

// CustomHooks.js
import { useEffect, useState } from 'react';

export const useWindowWidthAndHeight = ()=>{
    // 1- Get the size of window 
    let windowInnerSize = [window.innerWidth, window.innerHeight];

    // 2- Define the state variable windowSize and pass windowInnerSize as its initial value
    let [ windowSize, setWidowSize ] = useState(windowInnerSize);

    useEffect(()=>{
        const changeWindowSize = ()=>{
            setWidowSize([window.innerWidth, window.innerHeight]);
        }
        /* 3- add a 'resize' eventListener to window so that whenever 
the size of window changes the state variable windowSize changes and the component re-renders */
        window.addEventListener("resize", changeWindowSize);

        // 4- cleanup the 'resize' eventListener
        return ()=> window.removeEventListener('resize', changeWindowSize);
    }, []);
    // 5- return the window size
    return windowSize;
}


여기에서 useWindowWidthAndHeight 라는 사용자 지정 후크를 만듭니다.

내부useWindowWidthAndHeight:
먼저 windowInnerSize 의 현재 너비와 높이를 저장할 window 변수를 만듭니다.
둘째, windowInnerSize Hook을 사용하여 생성한 상태 변수windowSize의 초기 값으로 useState를 사용합니다.
셋째, useEffect Hook을 선언하여 resize eventListner를 추가하여 창resize이 발생하면 changeWindowSize()가 화면의 새로운 측정windowSizewidth로 변경height하도록 합니다.
마지막으로 window 의 가장 최근에 측정된 너비와 높이를 반환합니다.

이제 헤더를 생성해 보겠습니다.

// Header.js
import React from 'react';
import Navbar from './Navbar';
import { Link } from 'react-scroll'; // react-scroll is a library for scrolling in React
import SmallScreensNavbar from './SmallScreensNavbar';
import { useWindowWidthAndHeight } from './CustomHooks';

const Header = () =>{
    // use our custom hook to get the the window size
    const [width, height] = useWindowWidthAndHeight();
    return(
        <header>
            <div className="header-inner">
                <Link to="Home" 
                      smooth={true} 
                      className="logo nav-link">
                      RH
                </Link>
                {/*if the width of the window is bigger than 1000px use <Navebar/>,
                   else user <SmallScreensNavbar/>*/}
                { width > 1000 ?
                <Navbar navClass="nav-big"
                        linkClassName="nav-big-link"/>
                :
                <SmallScreensNavbar navClass="nav-small"
                                    linkClassName = "nav-small-link"
                />
                } 
            </div>
        </header>
    )
}

export default Header;


이제 너비가 1000px보다 큰 화면과 작은 화면을 위한 두 개의 탐색 모음 구성 요소를 만들어야 합니다.

//Navbar.js
import React from 'react';
import { Link } from 'react-scroll';

const Navbar = ({navClass, linkClassName}) =>(
    <NavComponent navClass={navClass}
                  linkClassName = {linkClassName}
    />
);

export const NavComponent = ({onClick, navClass, linkClassName})=>(
  <nav className={navClass}>
      {["Projects", "About", "Contact", "Footer"].map(section=>
        <Link to={section}
              smooth={true}
              className={linkClassName}
              onClick={onClick}>
            {section}
        </Link>
      )}
  </nav>
)
export default Navbar;


작은 화면의 경우:

//SmallScreensNavbar.js
import React, { useState } from 'react';
import { NavComponent } from './Navbar';

const SmallScreensNavbar = () =>{
    // declare 'translate' as a state variable
    let [translate, setTranslate ] = useState(true);
    return(
        <div> 
             <button className="hamburger-btn"
                     onClick= {()=> setTranslate(!translate)}>  {/* toggle translate */}
                  {/* change the btn text based on whether translate is true or false */} 
                 {translate?<span>&#9776;</span>:<span>&times;</span>}
             </button>
             {/*hide and show the sidebar list based on whether translate is true or false*/}
             <div id="sidebar-list" className={`${translate? "addTransiton": "removeTransition"}`}>
                <NavComponent
                    navClass="nav-small"
                    linkClassName = "nav-small-link"
                    onClick = {()=>setTranslate(true)}  //set translate to true to hide the sidebar list
                />
             </div>
        </div>
    )
}
export default SmallScreensNavbar;


이제 이것이 작동하려면 CSS를 추가해야 합니다.

header{
    position: fixed;
    top: 0;
    height: 70px;
    background-color: rgb(197, 178, 178);
    width: 100%;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    box-shadow: 1px 1px 1px 1px rgba(116, 110, 110, 0.199);
}
.header-inner{
    width: 90%;
    display: flex;
    align-items: center;
    justify-content: space-between;
}
.hamburger-btn{
    font-size: 1.3rem;
    position: absolute;
    bottom: 0;
    width: 40px;
    height: 35px;
    right: 30px;
    outline: none;
    background-color: rgb(134, 125, 125);
    color: whitesmoke;
}
.addTransiton{
    transform: translateX(170px);
    transition: transform 0.5s ease-in-out;
}
.removeTransition{
    transform: translateX(20px);
    transition: transform 0.5s ease-in-out;
}

#sidebar-list{
    background-color: rgb(134, 125, 125);
    height: 90vh;
    width: 170px;
    position: absolute;
    z-index: 2000;
    right: 0;
    top: 0;
    margin-top: 70px;
}
.nav-big{
    list-style: none;
    display: flex;
    justify-content: space-around;
    width: 70%;
    font-weight: bold;
}

.nav-big-link{
   cursor: pointer;
   color: white;
   text-decoration: none !important;
}

.nav-small{
    display: flex;
    flex-direction: column;
    text-align: center;
    justify-content: space-around;
    margin: auto;
    height: 40%;
    margin-top: 50px;
    width: 80%;
}
.nav-small-link{
    cursor: pointer;
    color: whitesmoke;
    padding-bottom: 5px;
}



이제 모든 것이 작동해야 합니다.
읽어주셔서 감사합니다. :)

참조:
Stackoverflow 화면의 너비와 높이를 측정하는 방법을 알아보세요.

좋은 웹페이지 즐겨찾기