React로 블로그 만들기 (1) - Router로 페이지 추가하기

binary·2022년 2월 10일
14

React로 블로그 만들기 0

나는 많이 멍청해서 남들이 하지 말라는 거 다 하고 나서 깨닫는다.

아, 하면 안 되는 구나!

나말고 누군가의 말을 신용하지 못하는 것도 있지만 직접 겪어봐야 깨닫는 이상한 성격때문에 어쩔 수가 없다.

그래서 결론은! 리액트 진짜 뭔지 좆도 이해 못해서 블로그 만들면서 깨달아보려고 한다.


React로 블로그 만들기 1

블로그 생김새 계획

ㅎㅎ... 민망하지만... 그냥 구조만 잡아봤다. 디자인은 진행하면서 생각해보려고 한다.
아니면 원래 만들었던 블로그 디자인 그대로 가져가면서 싱글 페이지 앱으로 만들까, 아직 고민중이다.

React 설치

  1. npx create-react-app 프로젝트이름

  2. cd 프로젝트 이름

  3. yarn start

App.js 둘러보기

import logo from './logo.svg';
import './App.css';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;

<App> 이라는 이름을 가진 함수 컴포넌트인가 보다.

화면이 잘 뜨는 것을 확인했으니까 필요없는 <div className="App"> 아래 코드들은 다 지워야겠다.

index.js 둘러보기

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

App 컴포넌트를 불러와 여기서 사용하고 있다. 그리고 'root' 라는 곳에 App 컴포넌트를 render 하라는 것 같은데 'root' 는 어디에 있을까?

public 폴더의 index.html 둘러보기

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <!--
      manifest.json provides metadata used when your web app is installed on a
      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
    -->
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <!--
      Notice the use of %PUBLIC_URL% in the tags above.
      It will be replaced with the URL of the `public` folder during the build.
      Only files inside the `public` folder can be referenced from the HTML.

      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
      work correctly both with client-side routing and a non-root public URL.
      Learn how to configure a non-root public URL by running `npm run build`.
    -->
    <title>React App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <!--
      This HTML file is a template.
      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    -->
  </body>
</html>

body 태그 아래에 <div id="root"> 를 발견했다. 아마 여기에 App 컴포넌트를 그리는 것 같은데, 그러면 root 를 모든 컴포넌트의 부모라고 할 수도 있겠다.

폴더 구조 생각해보기

Router 를 이용하여 블로그를 만들 예정이기 때문에 Router 만 관리하는 컴포넌트가 있으면 좋을 것 같다고 생각한다.

그리고 최대한 App.js 파일은 깔끔하게 유지하기 위해 다 작게 작게 쪼개서 관리해보려고 한다.

위와 같은 폴더 구조로 만들 예정인데 살짝 달라질 수도 있을 것이다.

리액트 라우터

근데 라우팅이 뭐임?

웹과 앱에서의 라우팅은 사용자가 원하는 url에 맞는 화면을 보여주는 것을 말한다.

설치하기

npm i react-router

npm i react-router-dom

터미널에 입력해준다. 여기서 i 는 install을 뜻한다.
줄여 말하기 좋아하는 개발자들 ... 줄좋개

설치가 잘 되었는지 확인해볼까용

오 둘 다 잘 설치되었다.

router 버전 6을 사용할 것이다. 생각보다 많이 바뀐 듯하다.

아래의 글을 많이 참고하여 블로그를 만들 예정이다!

| 참고
React Router v6 튜토리얼 : velopert.log

page 만들기

정말 진부하게도 about, contact, start 메뉴를 만들 것이다. 조금 더 틀이 잡히고 나서 메뉴의 타이틀을 바꾸려고 한다.

❗️ 컴포넌트 이름의 첫 글자는 꼭 대문자로 !

AboutPage.jsx

import React from "react";

export default function AboutPage() {
  return (
      <h1>About</h1>
  );
}

ContactPage.jsx

import React from "react";

export default function ContactPage() {
  return <h1>Contact</h1>;
}

StartPage.jsx

import React from "react";

export default function StartPage() {
  return <h1>start</h1>;
}

Router.jsx 작성하기

BrowserRouter, Routes, Route 알아보기

Router 를 사용하려면 모든 링크를 <BrowserRouter> 로 감싸주어야 한다.

<BrowserRouter> 안에는 RoutesRoute 가 있다.

RoutesRoute 를 감싼다.

정리하자면, router 의 기본 생김새는 아래와 같다.

import { BrowserRouter, Routes, Route } from "react-router-dom"

<BrowserRouter>
  <Routes>
    <Route />
  </Routes>
</BrowserRouter>
  • <BrowserRouter> : nav, 페이지 같은 모든 것들을 이것으로 감싸야 한다.

  • Routes : 여러 개의 Route 를 감싸고 핸들링해주는 컴포넌트이다.

  • Route : <Route> 태그 안에는 path 와 그에 맞추어 보여줄 컴포넌트 를 설정할 수 있다.
    <Route path="url" element={<컴포넌트이름 />} />
    예) <Route path="/" element={<Start />} />
    ❗️ path가 / 일 때, <Start /> 라는 element 를 렌더하라는 뜻이다.

Link를 이용하여 메뉴 만들기

<nav>
  <Link to='/'>Start</NavLink>
  <Link to='/about'>About</Link>
  <Link to='/contact'>Contact</Link>
</nav>

여기서 Link<a href="/"> 와 비슷하게 쓰이고 비슷한 일을 한다.

다른 점이 있다면 <a> 태그는 브라우저가 refresh 되면서 페이지 이동이 되는데, <Link> 는 refresh 되지 않고 페이지 간 이동이 가능하다.

| 실행화면

페이지가 refresh 되지 않으면서 url만 바뀌는 것을 확인할 수 있다.

Link를 NavLink로 바꾸기

Link 가 아닌 NavLink 를 쓰면 조금 더 스타일 입히기가 편해진다.

리액트에서 자동적으로 NavLinkonClick() 이벤트도 주고 className도 지정해주어서 따로 className을 지정한다던가 이벤트 같은 걸 주지 않아도 된다.

<nav>
  <NavLink to='/'>Start</NavLink>
  <Link to='/about'>About</Link>
  <Link to='/contact'>Contact</Link>
</nav>

비교해보기 위해서 / (Start 컴포넌트) 만 <NavLink> 로 바꾸었고, 나머지는 <Link> 로 놔두었다.

  • <NavLink to='/'>Start</NavLink> Start 메뉴를 클릭했을 때

start 에 class="active" 가 생겼다.

  • <Link to='/contact'>Contact</Link> Contact 메뉴를 클릭했을 때

start의 class="active" 가 사라지고, contact에는 변화가 없다.

<NavLink> 를 사용하면 active 일 때 메뉴 버튼의 배경색을 다르게 한다던가, 그런 식으로 편하게 스타일을 입힐 수 있다.

++  className 에 함ㅁ수도 쓸 수 있다.

<NavLink className={({ isActive }) => "nav-link" + (isActive ? " click" : "")} to='/'>
  Start
</NavLink>

Router.jsx

import React from "react";
import { BrowserRouter, Routes, Route, NavLink } from "react-router-dom";
import AboutPage from "./pages/About/AboutPage";
import ContactPage from "./pages/Contact/ContactPage";
import StartPage from "./pages/Start/StartPage";

export default function Router() {
  return (
    <BrowserRouter>
      <nav>
        <NavLink className={({ isActive }) => "nav-link" + (isActive ? " click" : "")} to='/'>
          Start
        </NavLink>
        <NavLink className={({ isActive }) => "nav-link" + (isActive ? " click" : "")} to='/about'>
          About
        </NavLink>
        <NavLink className={({ isActive }) => "nav-link" + (isActive ? " click" : "")} to='/contact'>
          Contact
        </NavLink>
      </nav>

      <Routes>
        <Route exact path='/' element={<StartPage />} />
        <Route path='/about' element={<AboutPage />} />
        <Route path='/contact' element={<ContactPage />} />
      </Routes>
    </BrowserRouter>
  );
}

Rouer.jsx 를 이렇게 완성시켰다.

App.js

import "./App.css";
import Router from "./Router";

function App() {
  return (
    <div className='App'>
      <Router />
    </div>
  );
}

export default App;

App.js<Router /> 컴포넌트를 불러왔다.

| 실행화면

메뉴를 누르면 메뉴에 해당하는 컴포넌트의 내용이 refresh 되지 않고 보여진다.

왕 신기하다!

아직 스타일을 먹이지 않아서 이상하게 보이는데 앞으로 점점 다듬으면서 변화를 줄 생각이다!

1개의 댓글

comment-user-thumbnail
2022년 11월 4일

저도 아무것도 모르는 상태로 리액트로 블로그 좀 만들어보려다 들어오게되었는데 재밌게 잘 봤습니다 ㅎㅎㅎ

답글 달기