React

[React] 서브페이지 추가하기

코드비버 2025. 2. 17. 23:54

리액트를 사용하지 않고 홈페이지를 만드는 경우엔 보통 메인 페이지 html 파일과 서브 페이지 html 파일을 폴더로 구분해 작성하며, 링크 주소 또한 폴더 구조에 따라 정해진다.

하지만 SPA(Single Page Application) 방식의 웹을 제작하는 리액트에선 각 페이지를 폴더 구조에 따라 구분하지 않는다.

 

SPA가 뭔데?

이번 포스팅은 SPA 개념을 설명하기 위한 것은 아니기에 간단하게 요약하자면, 웹이 최초로 구동되었을 때 웹페이지에 필요한 모든 리소스를 다운받고, 이후 사용자의 요청이 있을 때 마다 하나의 페이지에서 필요한 영역만 리렌더링하는 방식이다.

자세한 설명은 아래의 링크를 참고하면 좋을것 같다.

 

https://www.tcpschool.com/react/intro_understanding

 

코딩교육 티씨피스쿨

4차산업혁명, 코딩교육, 소프트웨어교육, 코딩기초, SW코딩, 기초코딩부터 자바 파이썬 등

tcpschool.com

 

그럼 서브페이지의 경로는 어떻게 설정할까?

제작중인 홈페이지의 헤더와 서브 페이지 목록

 

처음엔 단순하게 각 서브페이지에 해당하는 jsx 파일을 만들어 라우트 경로를 지정해주면 된다고 생각했고, 실제로 관심매물 찜하기 페이지도 그렇게 구현했다.

//App.jsx 일부

<Routes>
  <Route path="/" element={<Home />} />
  <Route path="/interest" element={<Interest />} />
</Routes>

 

하지만 위 코드에 나머지 16개의 라우트 경로를 일일이 추가한다면 코드 가독성도 떨어지고 추후 각 메뉴에 페이지 추가 및 삭제 등의 변동이 있을 때마다 최상위 컴포넌트인 App.jsx까지 함께 수정해야 하기에 유지보수 측면에서 번거로움이 생길 것이다.

따라서 네 개의 큰 메뉴 안에 서브페이지 이름을 추가하는 구조로 경로를 설정할것이다.

//App.jsx 일부

<Routes>
  <Route path="/" element={<Home />} />
  <Route path="/interest" element={<Interest />} />
  <Route path="/model/:subPageName" element={<Model />} />
  <Route path="/used-car/:subPageName" element={<UsedCar />} />
  <Route path="/service/:subPageName" element={<Service />} />
  <Route path="/brand/:subPageName" element={<Brand />} />
</Routes>

 

이후 Header 안의 리스트에 직접 onClick 이벤트를 지정해 경로를 완성하면 된다.

//Header.jsx

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

const Header=()=>{
    const nav=useNavigate();
    
    return (
        <ul className='depth02'>
            <li onClick={()=>{nav('/model/hatch')}}>HATCH</li>
            <li onClick={()=>{nav('/model/5door')}}>5-DOOR</li>
            <li onClick={()=>{nav('/model/convertible')}}>CONVERTIBLE</li>
            <li onClick={()=>{nav('/model/clubman')}}>CLUBMAN</li>
            <li onClick={()=>{nav('/model/countryman')}}>COUNTRYMAN</li>
        </ul>
    );
}

 

만약 헤더에서 Model 메뉴 아래의 HATCH 메뉴를 클릭하면 로컬 경로 기준으로 Model.jsx 페이지가 http://localhost:5173/model/hatch 경로로 열릴것이다.

 

서브페이지 구현

현재 만들고 있는 홈페이지 기준으로 Model 메뉴에 총 5개의 서브페이지가 있는데, useParams Hook을 통해 얻어낸 paramsName 기준으로 각각 다른 내용이 렌더링되도록 만들 것이다.

참고로 Header, SubMain, QuickMenu, Footer는 모든 서브페이지에서 사용되는 공통 요소이다.

// Model.jsx

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

import Header from "../components/Header";
import SubMain from "../components/sub/SubMain";
import ModelContent from "../components/sub/model/ModelContent";
import QuickMenu from "../components/QuickMenu";
import Footer from "../components/Footer";

const Model=()=>{
    const params=useParams();
    const paramsName=params.subPageName;

    return (
        <>
            <Header />
            <SubMain />
            <ModelContent paramsName={paramsName} />
            <QuickMenu />
            <Footer />
        </>
    );
}

export default Model;
//ModelContent.jsx

import './ModelContent.css';

import Hatch from './Hatch';
import FiveDoor from './FiveDoor';
import Convertible from './Convertible';
import Clubman from './Clubman';
import Countryman from './Countryman';

const ModelContent=({paramsName})=>{
    switch(paramsName){
        case 'hatch' : return <Hatch />
        case '5door' : return <FiveDoor />
        case 'convertible' : return <Convertible />
        case 'clubman' : return <Clubman />
        case 'countryman' : return <Countryman />
        default : break;
    }
}

export default ModelContent;
//Hatch.jsx

import HatchImg from '../../../assets/sub/model_hatch.jpg';

const Hatch=()=>{
    return (
        <section className="ModelContent">
            <div className="inner_1280">
                <h4 className='mb_sm'>MINI HATCH</h4>
                <h5 className='fs_lg mb_lg'>(타이틀 생략)</h5>
                <img src={HatchImg} alt="미니 해치" className='mb_lg' />
                <p>
                    (텍스트 생략)
                </p>
            </div>
        </section>
    );
}

export default Hatch;

 

Model.jsx 페이지에서 얻은 paramsName을 가지고 ModelContent.jsx 컴포넌트에서 5개 모델의 컴포넌트 중 적절한 것을 찾아 리턴하면 된다.

paramsName에 따라 각각 다른 내용이 렌더링되는 Model.jsx 페이지

 

예를 들어 paramsName이 'hatch'일 경우 ModelContent.jsx 컴포넌트 영역에서 그에 맞는 Hatch.jsx 컴포넌트를 리턴해주는 것이다.

마찬가지로 paramsName이 '5door'인 경우 FiveDoor.jsx 컴포넌트를, 'convertible'인 경우 Convertible.jsx를 리턴한다.

 

P.S.

사실 이번 포스팅은 작성하기 전까지 고민을 좀 했었는데, 서브페이지를 구현하는 방법이 이게 맞는지 확신이 서지 않았기 때문이다.

지금 방식은 너무 마크업 위주의 jsx 파일이 남발되고 있는것 같아 이게 과연 리액트의 장점을 살리는 구조인지 의문이 들고있다.

이 부분은 좀 더 알아보고 다음 프로젝트때 더 나은 방법이 있다면 반영해봐야 할 것 같다.