이번 글에서는 리액트를 이용해서 사이드바를 접고 펼칠 수 있는 기능을 간단하게 구현해보자.

지난 글 React에서 인풋 필드 validate하기에서와 같은 방식으로, 리액트의 상태를 이용한 렌더링을 이용하면 상태를 바꿔주기만 해도 컴포넌트를 쉽게 바꿀 수 있다.

언제나 그렇듯이 새로운 예제 앱을 만들자.

$ create-react-app react-toggle-sidebar-example
$ cd react-toggle-sidebar-example && yarn start

프로젝트 폴더에서 필요하지 않은 모든 파일을 삭제한다.

먼저 App.js는 .app, .sidebar, .content 총 3개의 div가 필요하다.

App.js

...

render() {
  return (
    <div className="app">
      <div className="sidebar"></div>
      <div className="content"></div>
    </div>
  )
}

기본적인 페이지 레이아웃을 잡아줘야 하기 때문에 App.js에서 App.css 파일을 불러오자.

App.js

import React, { Component } from 'react';
import './App.css';

그리고 App.css를 다음과 같이 작성한다.

body {
  margin: 0;
  padding: 0;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
    sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.app {
  min-height: 100vh;
  display: flex;
}

.sidebar {
  width: 200px;
  padding: 17px 10px 0;
  background: black;
  color: white;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.collapsed {
  width: 60px;
}

.content {
  width: 100%;
  padding: 0 20px 0;
}

이제 App.js로 돌아가서 각 div에 내용을 채워넣어보자.

App.js

class App extends Component {
  render() {
    return (
      <div className="app">
        <div className="sidebar">
          <span
          role="presentation"
          >
            사이드바 접기
          </span>
          <ul>
            <li>Menu Item 1</li>
            <li>Menu Item 2</li>
            <li>Menu Item 3</li>
            <li>Menu Item 4</li>
            <li>Menu Item 5</li>
          </ul>
        </div>

        <div className="content">
          <p>
            Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
            eiusmod tempor incididunt ut labore et dolore magna aliqua. Accumsan
            sit amet nulla facilisi. Sed faucibus turpis in eu mi bibendum
            neque. Egestas quis ipsum suspendisse ultrices gravida dictum fusce
            ut placerat. Semper eget duis at tellus at urna condimentum mattis.
            Ipsum a arcu cursus vitae congue. Cras pulvinar mattis nunc sed
            blandit libero volutpat sed. Turpis massa sed elementum tempus
            egestas sed.
          </p>
          <p>
            Pretium fusce id velit ut tortor. Sit amet justo donec enim diam. Et
            tortor consequat id porta nibh venenatis cras sed. Nec ullamcorper
            sit amet risus nullam eget felis eget. Ultrices sagittis orci a
            scelerisque purus semper eget duis at. Consectetur libero id
            faucibus nisl tincidunt eget nullam. Sed blandit libero volutpat sed
            cras ornare arcu dui. Urna cursus eget nunc scelerisque viverra
            mauris in aliquam sem. Ante in nibh mauris cursus mattis molestie a.
          </p>
          <p>
            In eu mi bibendum neque egestas congue quisque egestas. Dictum at
            tempor commodo ullamcorper a lacus vestibulum sed. Venenatis tellus
            in metus vulputate eu scelerisque felis imperdiet proin. Elit
            scelerisque mauris pellentesque pulvinar pellentesque habitant morbi
            tristique. Volutpat ac tincidunt vitae semper quis lectus nulla at.
            Id interdum velit laoreet id donec. Hac habitasse platea dictumst
            quisque sagittis. Vitae congue mauris rhoncus aenean vel elit
            scelerisque.
          </p>
          <p>
            Eget nulla facilisi etiam dignissim diam. Pellentesque diam volutpat
            commodo sed egestas egestas. Facilisis magna etiam tempor orci eu
            lobortis elementum. Nam aliquam sem et tortor consequat id porta
            nibh. Sagittis aliquam malesuada bibendum arcu vitae elementum
            curabitur. In pellentesque massa placerat duis. Volutpat est velit
            egestas dui id ornare arcu odio ut. Nunc non blandit massa enim nec
            dui nunc mattis enim. Enim ut sem viverra aliquet eget sit amet
            tellus cras. Vitae congue eu consequat ac felis donec et. Urna duis
            convallis convallis tellus id interdum.
          </p>
        </div>
      </div>
    )
  }
}

여기까지 잘 따라왔다면 다음과 같은 화면이 나올 것이다.

ul/li가 못 생겼다. 다음을 App.css에 추가하자.

ul {
  padding-inline-start: 0;
}

li {
  list-style-type: none;
}

ul/li가 한결 보기 나아졌다

이제 기본 세팅은 끝났다. 이제 App.js에 사이드바를 접고 펼 수 있는 상태를 만들고 각 상태별로 다른 컴포넌트를 렌더해보자.

App.js

class App extends Component {
  state = {
    isSidebarExpanded: true
  };

  sidebarExpanded = () => (
    <div className="sidebar">
      <span
        role="presentation"
        onClick={() => this.setState({ isSidebarExpanded: false })}
      >
        사이드바 접기
      </span>
      <ul>
        <li>Menu Item 1</li>
        <li>Menu Item 2</li>
        <li>Menu Item 3</li>
        <li>Menu Item 4</li>
        <li>Menu Item 5</li>
      </ul>
    </div>
  );

  sidebarCollapsed = () => (
    <div className="sidebar collapsed">
      <span
        role="presentation"
        onClick={() =>
          this.setState({
            isSidebarExpanded: true
          })
        }
      >
        펼치기
      </span>
      <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
      </ul>
    </div>
  );

  render() {
    const { isSidebarExpanded } = this.state;

    return (
      <div className="app">
        {isSidebarExpanded && this.sidebarExpanded()}
        {isSidebarExpanded || this.sidebarCollapsed()}
        <div className="content">
          <p>
            Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
            eiusmod tempor incididunt ut labore et dolore magna aliqua. Accumsan
            sit amet nulla facilisi. Sed faucibus turpis in eu mi bibendum
            neque. Egestas quis ipsum suspendisse ultrices gravida dictum fusce
            ut placerat. Semper eget duis at tellus at urna condimentum mattis.
            Ipsum a arcu cursus vitae congue. Cras pulvinar mattis nunc sed
            blandit libero volutpat sed. Turpis massa sed elementum tempus
            egestas sed.
          </p>
          <p>
            Pretium fusce id velit ut tortor. Sit amet justo donec enim diam. Et
            tortor consequat id porta nibh venenatis cras sed. Nec ullamcorper
            sit amet risus nullam eget felis eget. Ultrices sagittis orci a
            scelerisque purus semper eget duis at. Consectetur libero id
            faucibus nisl tincidunt eget nullam. Sed blandit libero volutpat sed
            cras ornare arcu dui. Urna cursus eget nunc scelerisque viverra
            mauris in aliquam sem. Ante in nibh mauris cursus mattis molestie a.
          </p>
          <p>
            In eu mi bibendum neque egestas congue quisque egestas. Dictum at
            tempor commodo ullamcorper a lacus vestibulum sed. Venenatis tellus
            in metus vulputate eu scelerisque felis imperdiet proin. Elit
            scelerisque mauris pellentesque pulvinar pellentesque habitant morbi
            tristique. Volutpat ac tincidunt vitae semper quis lectus nulla at.
            Id interdum velit laoreet id donec. Hac habitasse platea dictumst
            quisque sagittis. Vitae congue mauris rhoncus aenean vel elit
            scelerisque.
          </p>
          <p>
            Eget nulla facilisi etiam dignissim diam. Pellentesque diam volutpat
            commodo sed egestas egestas. Facilisis magna etiam tempor orci eu
            lobortis elementum. Nam aliquam sem et tortor consequat id porta
            nibh. Sagittis aliquam malesuada bibendum arcu vitae elementum
            curabitur. In pellentesque massa placerat duis. Volutpat est velit
            egestas dui id ornare arcu odio ut. Nunc non blandit massa enim nec
            dui nunc mattis enim. Enim ut sem viverra aliquet eget sit amet
            tellus cras. Vitae congue eu consequat ac felis donec et. Urna duis
            convallis convallis tellus id interdum.
          </p>
        </div>
      </div>
    );
  }
}

먼저 true를 기본값으로 갖고 있는 isSidebarExpanded라는 상태를 하나 만든다. isSidebarExpanded가 true일 때 그리고 false일 때를 나누어서 펼쳐진 사이드바와 접힌 사이드바를 렌더할 것이다.

그리고 expandSidebar 함수는 펼쳐진 사이드바를 렌더하는 함수이고 ‘사이드바 접기’ 라는 텍스트에 onClick 이벤트를 넣어서, 클릭 시 isSidebarExpanded 상태를 false로 변환한다.

반대로 collapseSidebar 함수는 접힌 사이드바를 렌더하는 함수이다. ‘펼치기’ 텍스트를 클릭시 isSidebarExpanded 상태가 true가 된다.

마지막으로 렌더 함수 안에 사이드바 자리에서 isSidebarExpanded 상태가 true일 때 sidebarExpanded 함수를 실행시켜 펼쳐진 사이드바를 렌더한다. 그리고 isSidebarExpanded 상태가 false일 때는 sidebarCollapsed 함수를 실행시켜 접힌 사이드바를 렌더한다.

완성된 사이드바 열고 닫기 (마우스 커서가 보이지 않는다)

예제 프로젝트의 코드와 라이브 데모는 다음 링크에서 확인할 수 있다.