[React] 반응형 헤더 만들기 (feat. useState)

🌊·2022년 1월 4일
6

React

목록 보기
16/20

React Hook의 useState를 이용해서 반응형 헤더와 메뉴 동작을 만들어보려고 한다.
useStateCSS 속성 값을 바꿔서 메뉴가 동작하는 것처럼 보일 수 있다.

Web 화면

Mobile 화면

App.js - import

import React, { useState } from "react";
import styled from "styled-components";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faApple } from "@fortawesome/free-brands-svg-icons";
import { faBars, faUser, faTimes } from "@fortawesome/free-solid-svg-icons";

아이콘을 쉽게 가져올 수 있는 Fontawesome 설치가 필요하다.
CSSstyled-components를 사용했다.

jsx 구조

├── Header
│   ├── toggle Button
│   ├── logo
│   ├── user Button
│   ├── header__menulist
│   └── header__right

jsx 구조를 이렇게까지 작성한 이유는 반응형을 구현하기 위해서 부모, 자식 관계나 순서가 꽤나 중요했다.
아직 CSS가 미숙한 부분일수도 있지만, 위의 구조처럼 진행했을 때 좀 더 수월하게 반응형 헤더를 구현할 수 있었다.

웹 화면에서는 toggle ButtonuserButtondisplay:none;으로 되어있다.
반응형이 적용되는 화면에서는 toggleButtonuserButtondisplay:block;으로 되고 header__menulistheader__rightdisplay:none;으로 된다.
이 상황에서 header__menulistheader__rightdisplay 속성이 flex로 바뀌게 되면서 width:100% 속성을 적용하면 자연스럽게 toggle Button, logo, userButton 아래로 내려갈 수 있다.

버튼 적용 화면


App.js - javascript

function App() {
  const [isToggled, setIsToggled] = useState(false);
  const [userToggled, setUserToggled] = useState(false);

  return (
    <Header isToggled={isToggled} userToggled={userToggled}>
      {/* 햄버거 버튼(bar) */}
      <div
        className="toggle"
        onClick={() => {
          setIsToggled(!isToggled);
        }}
      >
        <FontAwesomeIcon icon={!isToggled ? faBars : faTimes} />
      </div>

      {/* Apple 로고 */}
      <div className="logo">
        <FontAwesomeIcon icon={faApple} />
      </div>

      {/* User 버튼 */}
      <div
        className="user"
        onClick={() => {
          setUserToggled(!userToggled);
        }}
      >
        <FontAwesomeIcon icon={!userToggled ? faUser : faTimes} />
      </div>

      {/* 메뉴 리스트 */}
      <ul className="header__menulist">
        <li>Mac</li>
        <li>iPad</li>
        <li>iPhone</li>
        <li>Watch</li>
        <li>Music</li>
        <li>고객지원</li>
      </ul>

      {/* User 메뉴 리스트 */}
      <ul className="header__right">
        <li>Login</li>
        <li>Register</li>
      </ul>
    </Header>
  );
}

export default App;

App.js - CSS

const Header = styled.div`
  max-width: 1280px;
  margin: 0 auto;
  display: flex;
  justify-content: space-between;
  align-items: center;
  color: white;
  background-color: black;

  .logo {
    margin: 0 1rem;
    font-size: 2rem;
  }

  .header__menulist {
    list-style: none;
    display: flex;
  }

  .header__left {
    display: flex;
  }

  .header__right {
    list-style: none;
    display: flex;
  }

  .header__right div {
    margin: 0 1rem;
  }

  li {
    padding: 0 1rem;
  }

  .toggle {
    display: none;
    font-size: 1.5rem;
    padding: 1rem 1rem;
  }

  .user {
    display: none;
    font-size: 1.5rem;
    padding: 1rem 1rem;
  }

  @media screen and (max-width: 768px) {
    flex-wrap: wrap;

    .header__right {
      display: ${(props) => (props.userToggled ? "flex" : "none")};
      flex-direction: column;
      width: 100%;
      background-color: black;
    }

    .header__menulist {
      display: ${(props) => (props.isToggled ? "flex" : "none")};
      flex-direction: column;
      width: 100%;
      background-color: black;
    }

    .header__menulist li,
    .header__right li {
      margin: 1rem 0;
      padding: 0;
    }

    .toggle {
      display: block;
    }

    .user {
      display: block;
    }
  }
`;

버튼 눌렀을 때 event 적용

jsx 부분

const [isToggled, setIsToggled] = useState(false);
const [userToggled, setUserToggled] = useState(false);

<div className="toggle"
  onClick={() => {
    setIsToggled(!isToggled);
  }}
>

<Header isToggled={isToggled} userToggled={userToggled}>

CSS 부분

@media screen and (max-width: 768px) {
  .header__right {
    display: ${(props) => (props.userToggled ? "flex" : "none")};
    flex-direction: column;
    width: 100%;
    background-color: black;
  }

  .header__menulist {
    display: ${(props) => (props.isToggled ? "flex" : "none")};
    flex-direction: column;
    width: 100%;
    background-color: black;
  }
}

useState를 통해서 isToggleduserToggled의 초깃값을 false로 지정한다.
onClick event가 실행됐을 때 해당 값을 반대로(false -> true) 바꾼다.
해당 값이 CSS 부분으로 전달되고 display 속성에 영향을 미친다.
CSS 부분으로 전달되는 것은 <Header isToggled={isToggled} userToggled={userToggled}>이 부분을 통해서 props로 전달할 수 있다.

onClick 이벤트로 바뀐 값을 CSS로 넘겨주는 부분에서 꽤나 많은 시간을 썼다.
onClick 이벤트로만 해당 기능이 작동하기 때문에 다른 영역을 선택한다고 display 속성이 바뀌지 않는다.

0개의 댓글