React와 Vite를 활용한 포트폴리오 사이트 제작기

들어가며

이전에 Flutter를 사용하여 앱을 개발한 경험은 있었지만, 웹 개발은 거의 해본 적이 없었다. 대학교 수업에서 HTML과 CSS를 간단히 배운 적은 있었지만, 제대로 된 웹 애플리케이션을 만들어 본 경험은 없었다.

그래서 이번 기회에 웹 개발을 깊이 있게 배우면서, 동시에 실질적인 결과물을 만들어보자는 목표를 세웠다.

처음에는 Flutter의 웹 지원 기능을 활용할지 고민했지만, 웹 개발에 최적화된 기술을 배우는 것이 더 낫겠다고 판단했다. 그래서 React를 선택했고, 빌드 도구로는 Vite를 사용하기로 했다.

💡 첫 프로젝트로 포트폴리오를 선택한 이유

  1. 실제로 사용할 수 있는 결과물을 만들고 싶었다.
  2. 기본적인 CRUD 작업과 다양한 React 기능을 실험해 보고 싶었다.
  3. 개인 브랜딩을 위한 좋은 시작점이라고 생각했다.

기술 스택 선택 이유

React + Vite

처음에는 Create React App(CRA)을 고려했지만, 다음과 같은 이유로 Vite를 선택했다.

  1. 빠른 개발 환경
    • HMR(Hot Module Replacement)이 매우 빠름
    • 프로젝트 초기 빌드 속도가 CRA보다 빠름
  2. 현대적인 개발 도구
    • ES modules을 활용한 효율적인 빌드를 지원
    • 설정이 간단
    • 활발한 커뮤니티가 존재

주요 사용 라이브러리

라이브러리용도선택 이유
React Router라우팅SPA 구현을 위한 대표적인 라이브러리
Bootstrap반응형 UI반응형 디자인을 간편하게 구현
React Icons아이콘다양한 아이콘을 쉽게 사용

React 생태계를 처음 접하는 입장에서 최대한 기본 기능을 활용하면서 필수적인 라이브러리만 추가하는 방향으로 개발을 진행했다.

개발 과정에서의 어려움

1. React의 컴포넌트 사고방식에 적응하기

Flutter에서는 위젯을 활용해 UI를 구성했지만, React의 컴포넌트 시스템은 동작 방식에 있어 조금 달랐다.

  • 어떤 부분을 컴포넌트로 분리해야 할지 고민이 필요했다.
  • 상태(state)를 어디에서 관리할지 결정하는 것이 쉽지 않았다.
  • props와 state의 차이를 완전히 이해하는 데 시간이 걸렸다.

이러한 개념들을 익히는 데는 어느 정도 시간이 필요했다.

특히 부모-자식 컴포넌트 간 데이터 전달 방식은 Flutter의 Provider나 setState 패턴과는 미묘하게 다른 점들이 많아 처음엔 혼란스러웠다.

2. 상태 관리의 어려움

React는 상태 관리를 기본적으로 useState와 useContext 등을 통해 처리했다. 하지만 상태 업데이트가 비동기적으로 동작한다는 점이 익숙하지 않았다.

const [count, setCount] = useState(0);

const handleClick = () => {
  setCount(count + 1);
  console.log(count); // 예상: 1, 실제: 0
};

위 코드에서 console.log(count)의 값이 즉시 업데이트되지 않는다는 점이 처음에는 헷갈렸다.

이 문제를 해결하기 위해 함수형 업데이트를 사용하는 방법을 익혔다.

const handleClick = () => {
  setCount(prevCount => prevCount + 1);
};

React의 상태 업데이트가 비동기적으로 처리되기 때문에 이러한 방식이 필요하다는 것을 이해했다.

3. CSS 레이아웃 시스템 사용

Flutter에서 Column, Row, Expanded, Flexible 등의 위젯을 조합해서 UI를 구성했던 것과 달리, 웹에서는 flexbox, grid, position 같은 CSS 레이아웃 시스템을 사용해야 했다.

처음에는 Flutter와 비슷한 방식으로 생각하며 CSS를 적용했다가 원하는 대로 동작하지 않는 경우가 많았다.

예를 들어, Flutter에서는 Center 위젯이나 alignment 속성을 통해 간단하게 중앙 정렬할 수 있었다.

Center(
  child: Text("Hello World"),
)

하지만 CSS에서는 중앙 정렬 방식이 여러 가지로 나뉘어 있어서 다소 헷갈렸다.

특히 가로 중앙 정렬을 위해 margin: 0 auto;를 사용하는 방식이 처음에는 잘 이해되지 않았다.

.box {
  width: 200px;
  margin: 0 auto;
}

처음에는 위 코드가 모든 요소에 적용될 것이라 생각했지만, 실제로는 블록 요소(display: block;)에서만 적용된다는 사실을 알게 되면서 혼란스러웠다.

즉, inline, inline-block, flex, absolute 같은 다른 요소들에는 적용되지 않았고, 상황에 따라 다른 방법을 사용해야 했다.

Flutter에서는 한 줄로 해결되는 작업이, CSS에서는 요소의 display 속성에 따라 다르게 처리해야 한다는 점이 주요한 차이였다.

배운 점

1. 컴포넌트 설계의 중요성

  • 재사용성을 고려하여 컴포넌트를 설계했다.
  • props와 상태(state)를 적절히 구분하여 관리하는 연습을 했다.

2. 상태 관리 최적화

  • useState의 비동기적 동작 방식을 이해하게 되었다.
  • useEffect와 함수형 업데이트 패턴을 적절히 활용하는 방법을 익혔다.

3. CSS 레이아웃 원리 이해

  • Flexbox와 Grid를 활용해 반응형 UI를 구현했다.
  • DevTools를 적극 활용해 레이아웃 디버깅에 익숙해졌다.

4. 개발 워크플로 개선

  • Git을 이용한 버전 관리의 중요성을 체감했다.
  • 개발 과정에서의 문제 해결과정을 문서화하는 습관을 들였다.

마치며

Flutter로 개발하다가 React를 처음 접했을 때, “이게 왜 이렇게 동작하지?”라는 의문을 많이 가졌다.

하지만 점점 React의 컴포넌트 기반 개발 방식에 익숙해지면서, “이렇게 설계하면 재사용성이 좋아지겠구나”라는 감각을 익혔다.

"모든 전문가도 처음에는 초보자였다."

이 말을 되새기며 첫 프로젝트를 완성했다. 아직 부족한 점은 많지만, 이 경험을 바탕으로 더 성장할 수 있다고 느꼈다.

앞으로의 계획

  • TypeScript 도입
  • 테스트 코드 작성
  • 성능 최적화 방법 학습

참고 자료

  1. React 공식 문서
  2. Vite 공식 문서
  3. React Router 튜토리얼

댓글 0

댓글을 불러오는 중...

Follow Me