이 프로젝트 개발을 본격적으로 시작하기 위해서 어떤 기술스택을 쓰는게 좋을 지 생각해보았다.
인터넷을 찾아보니 Svelte/SvelteKit, React, Vue3, Solid.js등 다양한 추천들이 있었다.
SSURENT에서는 어떤 프론트 기술스택을 사용할까?
내가 선정한 기술스택은 Reat + TypeScript 조합이었다.


먼저 TS를 선택한 이유는 컴파일 전에 에러를 캐치할 수 있다는 장점이다.
만약 런타임에만 에러를 찾아낼 수 있었다면, 이 에러를 고치는 동안 대여사업 지속의 어려움이 생길 수 있겠다는 생각이 들었다.
TS를 사용한다고 해서 런타임 에러가 아예 발생하지 않는 것은 아니겠지만, 컴파일 시점에서 미리 에러를 캐치해서 몇가지 사항을 예방할 수 있는 것은 큰 이점이라고 생각했다.
두번째로 React를 선택한 이유는 방대한 생태계와 모바일 앱으로의 쉬운 전환, 취업 시장에서의 많은 수요이다.
React는 생태계가 방대하기 때문에 학습에 있어 쉽게 자료를 찾을 수 있고, React Native가 있기 때문에 모바일 앱으로의 전환 시에 보다 쉽게 코드를 재사용할 수 있다는 장점이 있다. 또한 최근 프론트엔드 개발 시장에서 React가 차지하는 비중또한 크기 때문에 나의 추후 커리어에서 도움이 될 것이라고 생각했다.
기술 스택 선정 이후에 깃허브도 만들고 피그마에서 디자인도 만들어서 본격적인 프론트엔드 개발에 들어갔다.
초반에는 디자인패턴에 대한 이해도가 없어서 막 작성하다가 디자인 패턴에 대해 알게 되었다.
다행히 정말 초반 단계라서 만들어놓은 디렉토리와 파일들이 적어서 금방 리팩터링 할 수 있었다.
내가 선택한 디자인 패턴은 Feature-Based Architecture이다.
이 디자인 패턴을 선택한 이유는 4가지이다.
1. 높은 응집도와 낮은 결합도 : 관련된 코드가 한 곳에 모여 있어 기능 개발과 유지보수가 효율적이다. 각 기능이 독립적으로 존재하여 다른 기능에 미치는 영향을 최소화할 수 있다.
2. 확장성과 모듈성 : 새로운 기능을 추가할 때 새로운 feature 폴더를 생성하면 되므로 확장이 용이하다. 각 기능을 독립적인 패키지로 분리하기도 쉽다.
3. 팀 협업 최적화 : 각 팀이나 개발자가 특정 feature를 담당할 수 있어 병렬 작업이 수월하고, 코드 충돌이 줄어든다.
4. 도메인 주도 설계(DDD) 친화적 : 비즈니스 도메인과 코드 구조가 일치하여 비즈니스 로직을 이해하기 쉽다.
출처 : https://jackerlab.com/feature-vs-layer-project-structure/
메인화면 디자인하기
전체적으로 UI구성은 피그마로 진행했다.
아래 이미지는 메인 화면에 대한 디자인 이미지이다.

메인 화면에 대한 구성은
페이지 이동 헤더 + 대여 / 반납 바로가기 버튼 + 대여사업 소개를 위한 요소들로 구성하였다.
추가로 난 디자인을 잘 못하기 때문에 CSS 라이브러리로 BootStrap을 이용하기로 했다.
Header 기능 구현하기
상단에 위치한 헤더는 메인 페이지 말고도 다른 페이지에서도 보여야 하는 컴포넌트이다.
따라서 share 패키지로 넣어주었다.
또한 로그인+회원가입 페이지에서는 로그인 버튼을 보이지 않게 하려고 했다.
원래는 모바일에서도 초기 디자인 한 화면처럼 길게 헤더를 구성하려 하였으나, 실제로 적용해봤을 때 누르기 힘들다는 점을 확인할 수 있었다.
그래서 다른 버튼(대여하기, 반납하기, 정보, 마이페이지, 로그인)은 햄버거 버튼으로 숨겨놓는것이 UX적으로 좋아보여서 수정하였다.
아래 두 상수는 현재 경로를 추적하기 위한 location과 모바일 메뉴의 열람정도를 판단하는 isOpen이다.
const location = useLocation();
const [isOpen, setIsOpen] = useState(false);
const hideLoginButton = location.pathname === '/login' || location.pathname === '/changePW';
hideLoginButton은 location이 로그인이나 비밀번호 변경 페이지일 때, 로그인 버튼을 숨기기 위한 변수이다.
const linkClass = ({ isActive }: { isActive: boolean }) =>
"nav-link px-3 link-dark fw-bold" + (isActive ? " active" : "");
이 코드는 현재 사용자가 있는 페이지가 어디인지 알려주기 위한 코드로 isActive가 True일 때 화면에 어떤 페이지인지 표시하기 위해 사용했다.
메인화면에서는 딱히 쓸 일은 없고, 다른 페이지로 넘어갔을 때 텍스트로 표기하는 역할이다. (추후에 삭제할 수도)

아래 코드는 모바일 화면에서 햄버거 버튼을 제어하는 역할이다.
const toggleNavbar = () => setIsOpen(!isOpen);
const closeNavbar = () => setIsOpen(false);
초기값을 false로 해서 모바일로 들어왔을 때 햄버거 버튼이 열려있는 상태로 맞이하지 않도록 설정해주었다

로고 영역 구현하기
<NavLink
to="/"
className="d-flex align-items-center text-dark text-decoration-none"
onClick={closeNavbar}
>
<img src={logo} alt="로고 이미지" style={{width: '90px'}} className="img-fluid me-2"/>
<span className="fs-4">SSURENT</span>
</NavLink>
로고 영역은 위처럼 네비게이션 바 영역으로 설정했고, 눌렀을 때 홈 화면인 "/"으로 이동하도록 설정해주었다.
d-flex align-items-center로 로고와 텍스트를 가로로 나란히 배치해주었고,
text-decoration-none으로 링크 밑줄도 제거해주었다.
햄버거 버튼 구현하기
<button
className="navbar-toggler"
type="button"
onClick={toggleNavbar}
aria-controls="navbarNav"
aria-expanded={isOpen}
aria-label="Toggle navigation"
>
<span className="navbar-toggler-icon"></span>
</button>
<div className={`collapse navbar-collapse ${isOpen ? 'show' : ''}`} id="navbarNav">
버튼 타입으로 설정하고
onClick={toggleNavbar}으로 클릭하면 메뉴 토글을 열 수 있도록 설정했다.
aria-expanded={isOpen} 으로 열려있는 상태인지 확인하고 메뉴를 여닫는 역할이다.
navbar-toggler을 클래스명으로 지정함으로서 bootstrap에서 제공하는 햄버거버튼 css스타일로 적용할 수 있다.
가로가 991px이하인 경우 햄버거 버튼으로 활성화 해준다.
아래 collapse navbar-collapse 부분으로 isOpen이 true일 때만 토글을 활성화시키도록 설정해주었다.
나머지 네비게이션 메뉴 구현하기
<ul className="navbar-nav me-auto ms-lg-5 mb-3 mb-lg-0">
<li className="nav-item">
<NavLink to="/rent" className={linkClass} onClick={closeNavbar}>
대여하기
</NavLink>
</li>
<li className="nav-item">
<NavLink to="/return" className={linkClass} onClick={closeNavbar}>
반납하기
</NavLink>
</li>
<li className="nav-item">
<NavLink to="/info" className={linkClass} onClick={closeNavbar}>
정보
</NavLink>
</li>
<li className="nav-item">
<NavLink to="/mypage" className={linkClass} onClick={closeNavbar}>
마이페이지
</NavLink>
</li>
</ul>
{!hideLoginButton && (
<div className="text-center text-lg-end mt-2 mt-lg-0">
<NavLink to="/login" onClick={closeNavbar}>
<button type="button" className="btn btn-outline-primary w-100" style={{maxWidth: '200px'}}>
로그인
</button>
</NavLink>
</div>
)}
각 항목들을 클릭하면 해당 페이지로 이동하고 모바일 메뉴라면 자동으로 닫히도록 구현했다.
로그인 버튼은 초기 구상한 것처럼 hide조건일 때 보이지 않게 구현했다.
전체 코드
아래는 내가 구성한 전체 코드이다.
import { NavLink, useLocation } from "react-router-dom";
import logo from "../../assets/images/ssulogo.jpg";
import "../../styles/App.css";
import {useState} from "react";
export default function Header() {
const location = useLocation();
const hideLoginButton = location.pathname === '/login' || location.pathname === '/changePW';
const [isOpen, setIsOpen] = useState(false);
const linkClass = ({ isActive }: { isActive: boolean }) =>
"nav-link px-3 link-dark fw-bold" + (isActive ? " active" : "");
const toggleNavbar = () => setIsOpen(!isOpen);
const closeNavbar = () => setIsOpen(false);
return (
<div className="container">
<nav className="navbar navbar-expand-lg py-3 mb-4 border-bottom">
<div className="container-fluid">
<NavLink
to="/"
className="d-flex align-items-center text-dark text-decoration-none"
onClick={closeNavbar}
>
<img src={logo} alt="로고 이미지" style={{width: '90px'}} className="img-fluid me-2"/>
<span className="fs-4">SSURENT</span>
</NavLink>
{/* 햄버거 버튼 (모바일에서만 보임)*/}
<button
className="navbar-toggler"
type="button"
onClick={toggleNavbar}
aria-controls="navbarNav"
aria-expanded={isOpen}
aria-label="Toggle navigation"
>
<span className="navbar-toggler-icon"></span>
</button>
<div className={`collapse navbar-collapse ${isOpen ? 'show' : ''}`} id="navbarNav">
<ul className="navbar-nav me-auto ms-lg-5 mb-3 mb-lg-0">
<li className="nav-item">
<NavLink to="/rent" className={linkClass} onClick={closeNavbar}>
대여하기
</NavLink>
</li>
<li className="nav-item">
<NavLink to="/return" className={linkClass} onClick={closeNavbar}>
반납하기
</NavLink>
</li>
<li className="nav-item">
<NavLink to="/info" className={linkClass} onClick={closeNavbar}>
정보
</NavLink>
</li>
<li className="nav-item">
<NavLink to="/mypage" className={linkClass} onClick={closeNavbar}>
마이페이지
</NavLink>
</li>
</ul>
{!hideLoginButton && (
<div className="text-center text-lg-end mt-2 mt-lg-0">
<NavLink to="/login" onClick={closeNavbar}>
<button type="button" className="btn btn-outline-primary w-100" style={{maxWidth: '200px'}}>
로그인
</button>
</NavLink>
</div>
)}
</div>
</div>
</nav>
</div>
);
}
'SSURENT(풀스택)' 카테고리의 다른 글
| [React + TS] 메인화면 구성하기 + Carousel (0) | 2025.11.19 |
|---|---|
| SSURENT 프로젝트 기획하기 (0) | 2025.11.18 |