말랑말랑제리스타일

React 프로젝트 Header, Footer, Sidebar 뼈대 만들기 본문

프로그래밍/웹코딩(html&JS)

React 프로젝트 Header, Footer, Sidebar 뼈대 만들기

제리제리 2024. 7. 12. 14:27

신규 프로젝트를 구상하면서 React JS로 Header, Footer, Sidebar가 있는 레이아웃을 만들 일이 생겼습니다.

React 화면 컨트롤은 Browser Router를 사용했고 이왕 만드는 거 다른 프로젝트에서 재사용 가능하도록 최대한 모듈을 구분해서 만들어봤습니다.

React 프로젝트 화면 구조 구상

React로 뼈대 구성할 구상도 그림 예시
React로 뼈대 구성할 구상도

일단 이번에 생성할 React 프로젝트의 레이아웃 뼈대는 요런식으로 만들 겁니다.

Header, Footer를 따로 빼고 메인 화면 좌측에 Sidebar를 넣어줄 예정이며, App Screen 부분을 Router를 이용해 이동시킬 겁니다.

 

React 프로젝트 레이아웃 뼈대를 잡기 위한 프로젝트 생성

먼저 VS Code와 node JS는 React를 해보신 분이라면 어렵지 않게 설치하실 테고, 이미 설치가 되어있을 거라 생각합니다.

CRA로 프로젝트 생성 후 필요한 패키지 설치

필요한 패키지는 기본적으로 CRA(Create React App)를 통해 설치되는 것 외에 React Router Dom을 사용할 겁니다.

React Router를 이용하기 위함입니다.

 

적당한 폴더로 가서 CRA를 이용해 프로젝트를 생성해 줍시다.

npx create-react-app my-project

많이들 해보셨을 거라 생각하고 "my-project"는 프로젝트 명칭입니다.

프로젝트 최상위 폴더 명이죠.

 

다음으로 React Router Dom을 설치할 겁니다.

터미널에서 my-project로 이동해 줍니다.

그리고 아래 명령어로 React Router Dom을 설치해 줍니다.

npm install react-router-dom

역시나 밥 먹듯 사용하는 npm 설치 명령어라 별게 없습니다.

 

마지막으로 필요 없는 파일을 삭제해 줍시다. public, node_modules 등 다른 폴더는 건드리지 않고 src 폴더 내에 있는

파일 중 App.css, App.js, index.css, index.js 빼고 다 삭제해 줍니다.

React 프로젝트 초기 상태
React 프로젝트 초기 상태

자 빨간색으로 지워둔 components 폴더를 제외하고는 이런 상태가 될 겁니다.

 

src 폴더 내에 components 폴더 생성

components 폴더 내에 Layout 폴더 생성

Layout 폴더 내에 Header.js, Footer.js, Layout.js 파일 생성

 

Layout에 사용할 Header, Footer 파일 생성

가장 간단한 Header, Footer 파일을 먼저 만들어줄 겁니다.

src 폴더 하단에 components 폴더를 하나 만들고 그 밑에 바로 Layout 폴더를 만들어줍니다.

Layout 폴더 하단에는 Header.js, Footer.js 파일을 각각 만들어줍니다.

지금부터는 소스 수정이 있을 건데 같은 소스를 여러 번 수정하는 과정이 있습니다.

따라서 해당 소스 파일의 마지막 상태는 최종이라고 표시하겠습니다.

사실 깃허브로 올려서 배포하기 귀찮은 게 그 이유입니다.

function Header({ title }) {
    return (
        <header>
            <h1>{title}</h1>
        </header>
    );
}

export default Header;

Header.js 파일 코드 (최종)

function Footer({ message }) {
    return (
        <footer>
            <span>{message}</span>
        </footer>
    );
}

export default Footer;

Footer.js 파일 코드 (최종)

 

Header의 타이틀과 Footer의 Message는 추후 재사용을 위해 파라미터로 받아주는 컴포넌트로 코딩해 줍니다.

정말 기본적인 React 소스코드라 별도 설명은 하지 않겠습니다.

 

Layout 파일 생성해서 Header, Footer 띄우기

Sidebar는 약간 복잡해지니까 일단 Layout 파일을 하나 만들어서 Header, Footer 파일을 띄워봅시다.

Layout 폴더 밑에 Layout.js 파일을 생성해 줍니다.

import Header from './Header';
import Footer from './Footer';

import { Outlet } from 'react-router-dom';

function Layout({title, footermessage}) {
    return (
        <div>
            <Header title={title} />
            <Outlet />
            <Footer message={footermessage} />
        </div>
    );
}

export default Layout;

Layout.js 파일 소스 코드

 

이런 식으로 코딩해 줍니다.

Header에는 title을 전달해 줄거고 Footer에는 footermessage를 전달해줄 겁니다.

여기서 Outlet 태그는 React에서 Router를 통해 전달받은 페이지를 띄우는 클래스로 상위에서 넘겨받은 페이지를 띄우기 위해서는 꼭 필요합니다.

 

이걸 화면에 띄우기 위해서는 Layout을 App.js 파일에서 호출해 주면 되겠죠.

App.js 파일을 열고 logo import 하는 부분 지우고, className이 App인 div 태그 안에 있는 건 전부 지워줍니다.

그리고 아래와 같이 코딩합니다.

import './App.css';
import {Routes, Route} from 'react-router-dom';

import Layout from './components/Layout/Layout';

function App() {
  const HeaderTitle = "React Router";
  const FooterMessage = "This is the footer message for the entire app.";
  return (
    <div className="App">
      <Routes>
        <Route element= {<Layout title={HeaderTitle} footermessage={FooterMessage} />}>
          <Route path="/" element={<h1>Home</h1>} />
          <Route path="about" element={<h1>About</h1>} />
          <Route path="services" element={<h1>Services</h1>} />
          <Route path="contact" element={<h1>Contact</h1>} />
        </Route>
      </Routes>
    </div>
  );
}

export default App;

App.js 파일 소스 코드

Routes에 최상위 Route로 Layout을 불러주고

Outlet에 들어갈 내용을 하위 Route로 넣어줍니다.

나중에 Page로 구성해 주면 되긴 하지만 일단은 태그만 넣어서 전달해 줍시다.

 

마지막으로 index.js 파일에 web vital은 삭제했으므로 소스에서도 지워줍시다.

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import { BrowserRouter as Router } from 'react-router-dom';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <Router>
      <App />
    </Router>
  </React.StrictMode>
);

index.js 파일(최종)

 

추가로 BrouserRouter로 App을 감싸줍니다.

(상단에 Alias 명을 Router로 사용했기 때문에 Router라고 사용함)

여기까지 끝났다면 npm start 명령어를 터미널에 입력해서 실행해 봅시다.

 

Header와 Footer를 넣은 실행화면

와우 잘 동작합니다.

http://localhost:3000/about 주소로 들어가면 라우터가 Outlet 영역만 바꿔준 것도 볼 수 있죠.

 

여기까지 Header와 Footer 넣는 건 성공적입니다.

 

근데 좀 아쉬운 게 Header와 Footer 영역을 좀 구분해서 보고 싶네요.

css플 좀 손대봅시다.

 

Header와 Footer에 Layout 적용시키기

Layout 폴더 하단에 Layout.module.css 파일을 하나 생성해 줍시다.

header {
    background-color: yellowgreen;
    color: white;
    border-bottom: 1px solid #d6d5d5;
    justify-content: flex-start;
    height: 3.5rem;
    display: flex;
    align-items: center;
    padding-left: 1rem;
}

footer {
    background-color: yellowgreen;
    color: black;
    border-bottom: 1px solid #d6d5d5;
    justify-content: flex-end;
    height: 2.5rem;
    display: flex;
    align-items: center;
    padding-right: 1rem;
}

Layout.module.css 파일

 

아까 유심히 보신 분들은 아시겠지만 Header와 Footer는 각각 header, footer 태그로 작성되었습니다.

이 태그는 자주 쓰이는 게 아니다 보니 태그에다가 스타일을 적용시켜 줍니다.

 

그러고 나서 Layout.js 파일에 styles로 import 시켜주기만 하면 바로 스타일이 적용됩니다.

import Header from './Header';
import Footer from './Footer';

import { Outlet } from 'react-router-dom';

import styles from './Layout.module.css';

function Layout({title, footermessage}) {
    return (
        <div>
            <Header title={title} />
            <Outlet />
            <Footer message={footermessage} />
        </div>
    );
}

export default Layout;

Layout.js 소스 코드

 

이렇게 import만 시켜주면 적용이 됩니다.

css 파일 적용한 예
css 파일 적용한 예

색깔이 찬란하고 눈이 부시긴 하지만 어쨌든 적용이 됐죠.

css 파일 background-color에서 바꾸시면 됩니다.

 

React 프로젝트에 Side Bar 만들기

자 이제 드디어 Side Bar 내비게이터를 만들어봅시다.

일단 Navigation Bar를 만들고 css를 이용해서 Side Bar 형태로 왼쪽에 밀어줄 겁니다.

Layout 폴더 밑에 Sidebar.js 파일을 생성해 줍시다.

참고로 Sidebar 역시 메뉴 리스트를 App.js에서 Layout.js를 통해 파라미터로 전달받을 예정입니다.

import { Link } from "react-router-dom";

function Sidebar({ menu_list, styles}) {
    return (
        <div>
            <nav className={styles.sideNavbar}>
                {menu_list.map((menu,index) => (
                    <div key={index} className={styles.sidebarItem}>
                        <Link to={menu.url} className={styles.sidebarLink} >
                            <span>{menu.title}</span>
                        </Link>
                    </div>
                ))}
            </nav>
        </div>
    );
}

export default Sidebar;

Sidebar.js 파일 소스 코드 (최종)

Link라는 React Router Dom에서 제공하는 태그를 사용하고 menu_list와 style은 Layout에서 전달받을 겁니다.

menu_list를 map으로 루프 돌면서 div로 감싸진 Link 태그를 만들어주는 거죠.

styles를 전달받는 목적은 Sidebar.module.css 파일을 따로 만들지 않고 Layout에서 상속받을 거 기 때문입니다.

 

다음으로 Layout에 Sidebar를 생성하는 소스를 추가합니다.

import Header from './Header';
import Footer from './Footer';
import Sidebar from './Sidebar';

import { Outlet } from 'react-router-dom';

import styles from './Layout.module.css';

function Layout({title, footermessage, menu_list}) {
    return (
        <div>
            <Header title={title} />
            <div className={styles.page}>
                <Sidebar menu_list={menu_list} styles={styles} />
                <Outlet />
            </div>
            <Footer message={footermessage} />
        </div>
    );
}

export default Layout;

Layout.js 소스 코드(최종)

Outlet 태그 앞에 Sidebar를 추가하고 Header와 Footer 사이에 css 파일로 스타일을 줘야 하기 때문에 div로 감싸줍니다.

 

여기서 Layout이 menu_list를 파라미터로 받기 때문에 App.js 파일도 수정해 줘야겠죠.

import './App.css';
import {Routes, Route} from 'react-router-dom';

import Layout from './components/Layout/Layout';

function App() {
  const HeaderTitle = "React Router";
  const FooterMessage = "This is the footer message for the entire app.";
  const menu_list = [
    { menu_id: 1,title: "Home", url: "/" },
    { menu_id: 2,title: "About", url: "/about" },
    { menu_id: 3,title: "Services", url: "/services" },
    { menu_id: 4,title: "Contact", url: "/contact" }
  ];
  return (
    <div className="App">
      <Routes>
        <Route element= {<Layout title={HeaderTitle} footermessage={FooterMessage} menu_list={menu_list} />}>
          {menu_list.map((menu) => (
            <Route key={menu.menu_id} path={menu.url} element={<h1>{menu.title}</h1>} />
          ))}
        </Route>
      </Routes>
    </div>
  );
}

export default App;

App.js 파일(최종)

 

menu_list를 title과 url을 가진 리스트로 만들어서 Layout에다가 넘겨줍니다.

다른 Route 주소들도 이 menu list를 이용해서 넣어줘도 괜찮을 것 같아 Route도 동적으로 생성하도록 수정했습니다.

 

여기까지 왔다면 이제 Sidebar와 Layout 중 page div에 css만 적용해 주면 되는데요.

이쯤에서 한번 실행 결과를 봅시다.

CSS를 적용하기 전 Sidebar 상태 화면입니다.
CSS를 적용하기 전 Sidebar 상태

링크를 이용해서 링크와 메뉴 하단에 있는 내용들이 바뀌는 걸 볼 수 있죠.

완벽합니다. 이제 css 파일로 Sidebar 스타일만 적용해주면 됩니다.

Layout의 Sidebar 스타일 적용

현재 Layout.module.css 파일 내부에는 header와 footer에 대한 내용만 들어있죠.

css 파일에서는 태그와 id, class 별로 적용이 가능한데요.

styles로 불러와서 적용하는 경우 태그 별 적용시킨 style은 바로 적용이 되지만 class name이나 id에는 직접 연결을 시켜줘야 합니다.

그래서 앞선 Layout.js 코드에 class를 "page"가 아닌 styles.page 변수 형태로 넣어준 거죠.

 

다시 복기해서 우리가 앞에서 style을 적용하기 위해 사용한 class 명칭은 Layout.js와 Sidebar.js에서 각각 page, sideNavbar, sidebarItem, sidebarLink 이렇게 4가지죠.

 

Layout.module.css 파일로 돌아옵시다.

먼저 page 부분을 추가해 줄 텐데요.

.page {
    display: flex;
    flex-direction: row;
    min-height: 100vh;
}

Layout.module.css 파일에 추가한 소스

 

최소 높이를 잡아주고 디폴트로 column으로 되어있는 flex 방향을 row로 잡아줍니다.

저장을 해주면 Sidebar가 완성되었습니다.

근데 너무 만들다 만 거 같죠.

좀 성형을 시켜줍시다.

.sideNavbar {
    background-color: rgb(250, 232, 222);
    width: 150px;
    display: flex;
    flex-direction: column;
    height: 100%;
}

Layout.module.css 파일에 추가한 소스

 

sideNavbar에 너비 값을 주고 배경 색상을 넣어줬습니다.

그런데 화면이 커졌을 때는 sidebar 영역이 좀 더 커지면 보기가 좋을 것 같죠.

@media (min-width: 768px) {
    .sideNavbar {
        width: 300px;
    }
}

Layout.module.css 파일에 추가한 소스

 

이제 화면을 옆으로 늘리다 보면 768픽셀을 넘어갈 때 훅 커지는 것을 볼 수 있을 겁니다.

다음으로 Item도 좀 허접해 보이니 이쁘게 해 줍시다.

 

.sidebarItem {
    font-size: 0.9rem;
    padding-bottom: 0.5rem;
}

폰트를 키워주고 sidebar의 item별로 간격을 좀 줘봤습니다.

물론 더 키우고 싶은 분들은 더 줘도 됩니다.

.sidebarItem {
    text-align: left;
}

각 item들도 중앙 정렬 돼있는 게 마음에 안 들어서 왼쪽으로 몰아줬습니다.

취향 차이니 알아서 빼거나 넣으면 됩니다.

 

근데 또 보라색 줄로 이건 링크라고 광고하는 것 같은 게 마음에 안 드네요.

.sidebarItem .sidebarLink {
    text-decoration: none;
    color: rgb(102, 102, 102);
    padding: 0.5rem;
    display: block;
    transition: 0.3s;
}

sidebarItem 내부에 있는 sidebarLink 클래스에는 글자를 좀 꾸며주고 패딩을 줍시다.

text decoration을 none으로 바꾸면서 링크처럼 생긴 걸 지우고 글자 색과 패딩을 넣었습니다.

여기서 마우스 오버할 때 바뀌는 시간도 0.3초 정도 주는 게 이쁜 것 같이 transition도 0.3초 넣어봤습니다.

.sidebarItem .sidebarLink:hover {
    background-color: rgba(255, 255, 255, 0.4);
    color: rgb(0, 0, 0);
}

이번에는 마우스를 올렸을 때 메뉴가 돋보이게 해주는 스타일입니다.

hover를 이용해서 마우스가 올라가면 sidebar Link가 색이 바뀌도록 해봤습니다.

React Sidebar 최종 완성 화면
React Sidebar 최종 완성 화면

여기서 추가로 해볼 만한 건 아이콘을 넣어보거나, 선택된 메뉴를 표시해 주는 것 등일 것 같은데요.

아이콘이야 어렵지 않을 것 같고 선택된 메뉴를 표시해주는 기능은 State를 이용해야 돼서 다음에 시도해 보고 알려드리겠습니다.

개인적으로 심플하니 마음에 드네요.

Comments