카테고리 없음

[52일차]모던 웹 프론트엔드 개발 전략: 스타일링과 상태 관리

PARKpatchnotes 2025. 11. 24. 02:05

1. 컴포넌트 구조와 레이아웃 (Component Structure & Layout)

1.1 페이지 레이아웃 (Page Layout)

웹 애플리케이션에서 헤더(Header), 푸터(Footer), 사이드바(Sidebar)와 같이 모든 페이지에서 공통적으로 사용되는 구조를 '레이아웃'이라 한다. 리액트에서는 각 페이지마다 이러한 컴포넌트를 반복해서 작성하는 대신, 공통 레이아웃 컴포넌트를 만들어 재사용성을 높이는 방식을 채택한다.

1.2 Children Props

리액트 컴포넌트가 태그 사이에 포함된 내용을 전달받기 위해 사용하는 특수한 prop이 children이다. 레이아웃 컴포넌트를 구현할 때 핵심적인 역할을 한다.

활용 예시:

<Layout>
  <MainPage />
</Layout>

위와 같이 작성하면, Layout 컴포넌트 내부에서 {children}을 통해 MainPage를 렌더링할 수 있다. 이는 컴포넌트의 합성을 가능하게 하여 유연한 UI 구조를 만든다.

2. CSS-in-JS 방법론

자바스크립트 코드 내에서 CSS를 작성하는 방식인 CSS-in-JS는 현대 웹 개발의 복잡성을 해결하기 위해 등장했다. 기존 CSS 방식이 가진 구조적 한계를 극복하기 위한 대안이다.

2.1 CSS-in-JS의 필요성과 해결 과제

기존의 CSS(또는 SCSS) 방식은 대규모 프로젝트에서 다음과 같은 문제점을 야기했다.

  • 스타일의 전역 충돌 (Global Namespace Collision): CSS 클래스 이름은 전역 스코프를 가진다. 서로 다른 컴포넌트에서 우연히 같은 클래스 이름을 사용할 경우 스타일이 깨지는 문제가 발생한다.
  • 의존성 관리의 어려움: 컴포넌트는 삭제되었지만 그에 해당하는 CSS 코드는 남아있는 경우가 많다. 어떤 스타일이 어디서 사용되는지 추적하기 어렵다.
  • 불필요한(중복된) 코드 발생: 사용하지 않는 스타일(Dead Code)이 번들에 포함되어 성능을 저하시킨다.
  • 압축(Minification)의 한계: 긴 클래스 이름을 유지해야 하는 경우가 많아 파일 크기를 줄이는 데 한계가 있었다.
  • 컴포넌트와 스타일의 상태 공유 어려움: 자바스크립트의 변수(상태)에 따라 스타일을 동적으로 변경하려면 복잡한 클래스 토글링이 필요했다.
  • 렌더링 순서와 명시도(Specificity) 문제: CSS 파일이 로드되는 순서에 따라 스타일 적용 우선순위가 달라져 예측 불가능한 결과가 나오기도 한다.
  • 캡슐화(Encapsulation) 부재: 컴포넌트의 스타일이 외부로 누수되거나 외부의 영향을 받지 않도록 격리하는 것이 어렵다.

CSS-in-JS는 스타일을 컴포넌트에 종속시켜 위 문제들을 해결하며, 캡슐화를 통해 독립적인 컴포넌트 개발을 보장한다. 또한 자동으로 고유한 클래스명을 생성하여 압축에 유리하다.

3. Styled Components

Styled Components는 CSS-in-JS를 리액트에서 구현하기 위한 가장 대중적인 라이브러리이다. 자바스크립트의 태그된 템플릿 리터럴(Tagged Template Literal) 문법을 사용하여 실제 CSS 문법 그대로 스타일을 작성할 수 있다.

3.1 전역 스타일 (Global Style)

CSS-in-JS는 컴포넌트 스코프에 스타일을 가두지만, body 태그의 배경색이나 폰트 설정과 같이 앱 전체에 적용해야 하는 스타일도 존재한다. Styled Components는 createGlobalStyle 유틸리티를 제공하여 CSS Reset이나 공통 폰트 정의와 같은 전역 스타일을 쉽게 처리할 수 있도록 한다.

4. 테마 시스템 (Theme System)

4.1 테마(Theme)와 ThemeProvider

테마란 색상 팔레트, 폰트 사이즈, 간격(Spacing) 등 디자인 시스템의 핵심 변수들을 모아놓은 객체이다. Styled Components는 ThemeProvider 컴포넌트를 제공하여, 이 테마 객체를 하위의 모든 컴포넌트가 쉽게 접근하여 사용할 수 있도록 한다.

4.2 테마를 사용하는 이유

테마 시스템을 도입함으로써 얻을 수 있는 이점은 다음과 같다.

  • UI/UX의 일관성: 모든 컴포넌트가 정의된 테마 변수만 참조하므로, 페이지 간 색상이나 여백이 달라지는 디자인 불일치를 방지한다.
  • 유지보수의 용이성: 브랜드 컬러가 변경될 경우, 테마 객체의 값 하나만 수정하면 애플리케이션 전체에 즉시 반영된다.
  • 확장성: 새로운 디자인 요구사항이 생겼을 때 테마에 키(key)를 추가하는 것만으로 대응이 가능하다.
  • 재사용성: 컴포넌트는 구체적인 색상 값(#ffffff) 대신 의미론적인 이름(theme.colors.background)을 사용하므로, 다른 프로젝트나 환경에서도 쉽게 재사용할 수 있다.
  • 사용자 정의 (다크 모드): 사용자가 원하는 색상 모드(Light/Dark)를 선택하면, ThemeProvider에 주입하는 테마 객체만 교체함으로써 손쉽게 다크 모드를 구현할 수 있다.

5. Context API와 전역 상태 관리

5.1 Context API의 개념

리액트의 기본 데이터 흐름은 부모에서 자식으로 props를 전달하는 단방향 방식이다. 하지만 테마 정보, 사용자 로그인 정보 등 애플리케이션 전역에서 필요한 데이터가 있을 때, 모든 컴포넌트를 거쳐 props를 전달하는 것(Props Drilling)은 비효율적이다.

Context API는 이러한 문제를 해결하기 위해 리액트가 제공하는 기능이다. 데이터(Context)를 생성하고 Provider로 감싸주면, 트리의 깊이와 상관없이 하위의 어떤 컴포넌트에서든 해당 데이터에 직접 접근할 수 있다. 이를 통해 전역적으로 데이터를 효율적으로 관리할 수 있다.

메모

버튼은 버튼끼리 리스트는 리스트끼리, 같은 요소끼리 모아서 하나의 theme.ts 에 모음, 그리고 theme 만 import해서 theme,tinybutton 이런식으로 사용해보자

```