섹션 사이 구분선, 컴포넌트 대신 플래그로

data-driven 렌더링 config 설계

reactdata-drivenconfig

난이도: ★★☆☆☆ 연관 노트: sessionStorage 대신 URL에 상태를 담는 이유


핵심 요약

  1. JSX 삽입 방식은 map을 사용하지 못하고 직접 나열하거나, map을 유지하려면 배열을 React.ReactNode 타입의 컴포넌트 나열로 바꿔야 한다.
  2. 플래그 방식은 divider 추가 시 수정하는 곳 = 해당 객체 값만 변경. JSX 삽입 방식은 배열에 새 컴포넌트 추가 + 배열 타입 변경까지 필요하다.
  3. 즉 플래그 방식은 변경이 데이터에 갇히고, JSX 삽입 방식은 변경이 렌더 구조까지 번진다.

왜 헷갈렸나

“관리가 편하다” 수준으로만 이해하고 있었다. 진짜 차이는 무엇을 수정하게 되는가였다 — 같은 “divider 하나 추가”인데 한쪽은 데이터 한 줄, 한쪽은 렌더 코드의 구조(배열 타입 포함)를 건드린다.


메커니즘

이미지 섹션을 나열하는 페이지에서 특정 섹션 앞에만 회색 구분 밴드가 필요했다.

선택지 A — JSX에 직접 삽입:

// map을 포기하고 직접 나열하거나
<Image src={a} />
<Image src={b} />
<Divider />          // ← 여기 끼우려고
<Image src={c} />

// map을 유지하려면 배열 자체를 ReactNode로
const items: ReactNode[] = [<Image .../>, <Divider />, <Image .../>];

선택지 B — 데이터에 플래그:

const SECTIONS: SectionItem[] = [
  { src: "a.png", alt: "..." },
  { src: "b.png", alt: "..." },
  { src: "c.png", alt: "...", dividerBefore: true }, // ← 이 줄만
];

{SECTIONS.map(({ src, alt, dividerBefore }) => (
  <Fragment key={src}>
    {dividerBefore && <Divider />}
    <Image src={src} alt={alt} />
  </Fragment>
))}

변경 파급 범위 비교:

              divider 1개 추가 시 수정 범위
플래그 방식    ──  데이터 배열의 객체 1개          (렌더 코드 불변)
JSX 삽입      ──  렌더 구조 + 배열 타입 + key 전략  (구조 변경)

렌더 로직은 “규칙”(dividerBefore면 앞에 밴드)을 한 번만 정의하고, 이후의 모든 변주는 데이터가 흡수한다.


해결 패턴

interface SectionItem {
  src: string;
  alt: string;
  /** 이미지 위에 구분선 렌더링 */
  dividerBefore?: boolean;
}

주의: 이것도 3번 규칙(반복 3회부터 추상화)의 지배를 받는다. divider 위치가 하나뿐이고 앞으로도 없을 게 확실하면 JSX 직접 삽입이 더 단순할 수 있다. 이번 케이스는 “동일 템플릿을 쓰는 페이지가 3개”라 데이터 주도가 명확히 이겼다 — 페이지마다 divider 위치가 달라도 렌더 코드는 공유된다.


다음에 이 상황을 만나면

리스트 렌더링 사이에 “가끔” 끼어드는 요소가 생기면 → map을 끊기 전에 “이 변주를 데이터로 표현할 수 있나?”를 먼저 묻는다.

  • 이 변주가 다른 아이템/다른 페이지에서도 반복될 수 있는가?
  • 렌더 규칙(플래그 → UI)을 한 문장으로 말할 수 있는가?
  • 플래그가 3개 이상 쌓이면 → 그때는 섹션 타입 분리(discriminated union)를 고려

커넥팅 닷

← 선행 개념 (이걸 알아야 이해된다)

  • 선언적 렌더링 — “무엇을 그릴지”를 데이터로 선언하고 렌더는 규칙만 갖는 React의 기본 사고
  • 관심사 분리(콘텐츠 vs 구조) — 콘텐츠(이미지 목록)는 페이지가, 구조(어떻게 나열할지)는 템플릿이 소유

→ 확장 개념 (여기서 더 나아가면)

  • Discriminated Union으로 섹션 타입 분기 — 플래그가 늘어나면 { type: "image" } | { type: "divider" } 형태로 진화시키는 것이 정석
  • 개방-폐쇄 원칙(OCP) — 렌더 코드는 수정에 닫혀 있고, 데이터 추가에는 열려 있는 구조

↔ 같은 원리가 적용되는 곳

  • sessionStorage 대신 URL에 상태를 담는 이유 — “상태/변주를 어느 레이어에 두느냐”가 유지보수 반경을 결정한다는 공통 구조
  • 라우트 config, 폼 스키마 렌더러 — 배열 config → 렌더 규칙 패턴의 대표 사례들

부록 — key 안정성

플래그 방식의 부수 이득: Fragment key={src}가 유지되므로 divider를 켜고 꺼도 이미지 노드의 key가 안 바뀐다. JSX 나열로 전환하면 index key로 밀리기 쉽고, 중간 삽입 시 이후 노드들이 전부 리마운트될 수 있다.