React 파워업: 리스트, 키, 그리고 컴포넌트 패턴 마스터하기! (React Day 4)

발행: (2026년 1월 12일 오후 01:30 GMT+9)
9 min read
원문: Dev.to

Source: Dev.to

위의 링크에 있는 전체 글을 번역하려면, 번역할 텍스트를 제공해 주세요. 현재 제공된 내용은 소스 링크만 포함되어 있어 번역할 본문이 없습니다. 텍스트를 복사해서 알려주시면 그대로 한국어로 번역해 드리겠습니다.

React에서 리스트

작동 방식
map()과 같은 배열 메서드를 사용해 데이터를 JSX로 변환합니다. 각 항목은 컴포넌트 또는 요소가 됩니다.

실용 예시: 기본 Todo 리스트

import { useState } from 'react';

function TodoList() {
  const [todos, setTodos] = useState(['Buy milk', 'Walk dog', 'Code React']);

  return (
    

      {todos.map((todo, index) => (
        - {todo}
 {/* Keys coming up next! */}
      ))}
    

  );
}

이 코드는 순서 없는 리스트를 렌더링합니다. 동적 업데이트를 위해 상태 업데이트(예: 폼을 통해)를 추가할 수 있습니다.

UI 시나리오

쇼핑 카트 앱에서:

{cart.map(item => (
  
))}

사용자는 항목을 추가/제거하고 UI가 원활하게 업데이트됩니다.

흔한 오류

빈 리스트를 처리하지 않으면 UI가 빈 화면이 될 수 있습니다. 조건부 렌더링을 추가하세요:

{todos.length ? (
  todos.map((todo, i) => - {todo}
)
) : (
  
No todos!

)}

모범 사례

매핑 로직을 단순하게 유지하고, 복잡한 항목은 가독성을 위해 서브‑컴포넌트로 분리합니다.


Keys

키는 key prop을 통해 리스트 아이템에 할당되는 고유한 문자열(또는 숫자)입니다. 컴포넌트에 전달되지 않으며, React 내부에서만 사용됩니다.

Why Keys Matter Internally

리컨실리에이션(React의 diff 알고리즘) 과정에서 키는 추가, 삭제, 변경된 아이템을 식별하는 데 도움을 줍니다. 안정적인 키가 없으면 React는 인덱스 기반 매칭으로 대체되며, 이 경우 잘못된 업데이트가 발생할 수 있습니다.

Performance Implications

올바른 키는 DOM 조작을 최소화합니다—React가 요소를 재생성하지 않고 재사용할 수 있기 때문입니다. 부적절한 키는 불필요한 재렌더링, UI 깜빡임, 컴포넌트 상태 손실(예: 입력 포커스)을 초래합니다.

Practical Example: Dynamic List with Stable Keys

function UserList({ users }) {
  return (
    

      {users.map(user => (
        - {user.name}
 {/* Use stable ID like a database key */}
      ))}
    

  );
}

users가 재정렬될 때, 키가 부드러운 전환을 보장합니다.

Common Errors

  • Using Index as Key – 정적 리스트에만 허용되며, 정렬 가능하거나 필터 가능한 리스트에서는 재앙이 됩니다.
  • Duplicate Keys – React가 경고를 표시합니다; 키는 형제 요소 사이에서 고유해야 합니다.
  • No Keys – 콘솔 경고가 발생하고 렌더링 효율이 떨어집니다.

UI Scenario

채팅 앱에서:

{messages.map(msg => (
  
))}

적절한 키가 없으면 스크롤이나 새로운 메시지 도착 시 포커스가 초기화되거나 애니메이션이 깨질 수 있습니다.

Best Practice

안정적이고 고유한 ID를 사용하세요(예: API에서 제공되는 ID). 매 렌더링마다 바뀌는 무작위 키는 피합니다.


컴포넌트 패턴

재사용 가능한 컴포넌트는 모듈화와 관심사의 분리를 촉진하는 명확한 패턴을 통해 이점을 얻습니다.

일반적인 패턴

  • 프레젠테이셔널 vs. 컨테이너 (스마트 vs. 덤) – 프레젠테이셔널 컴포넌트는 UI를 담당하고, 컨테이너는 로직(상태, 데이터 페칭)을 관리하며 데이터를 하위 컴포넌트에 전달합니다.
  • 복합 컴포넌트 – 암묵적인 상태를 공유하는 관련 컴포넌트를 그룹화합니다(예: ).
  • 렌더 프롭스 / HOC – 고급 재사용 기법이며, 훅이 더 간단한 대안을 제공하는 경우가 많습니다.

실용 예시: 컨테이너‑프레젠테이셔널 분리

// Presentational: Pure UI
function UserDisplay({ user }) {
  return Name: {user.name}, Age: {user.age};
}

// Container: Logic
import { useState, useEffect } from 'react';

function UserContainer() {
  const [user, setUser] = useState(null);

  useEffect(() => {
    // Simulate fetch
    setUser({ name: 'Alex', age: 28 });
  }, []);

  return user ?  : 
Loading...
;
}

UI 시나리오

대시보드에는 데이터를 가져와 ChartDisplay 컴포넌트에 전달하는 ChartContainer가 있을 수 있으며, 이를 통해 서로 다른 쿼리를 사용하는 페이지에서도 동일한 표시 로직을 재사용할 수 있습니다.

모범 사례

간단하게 시작하고, 컴포넌트가 성장함에 따라 패턴으로 리팩터링하세요. TypeScript는 재사용 가능한 컴포넌트의 prop 계약을 강제하는 데 도움이 될 수 있습니다.


Source:

관심사의 분리

UI와 로직, 상태와 렌더링을 구분하면 테스트, 디버깅, 협업이 더 쉬워집니다.

적용 방법

  • 로직을 추출하여 커스텀 훅이나 유틸리티 모듈에 넣습니다.
  • 컴포넌트를 집중시킵니다: 하나의 컴포넌트는 데이터를 가져오고, 다른 컴포넌트는 이를 렌더링합니다.

실용적인 예시

위의 UserContainer는 데이터 가져오기와 프레젠테이션을 분리합니다. 리스트 렌더링에도 같은 원칙을 적용할 수 있습니다: 훅이 사용자를 가져오고, UserList는 단순히 JSX로 매핑합니다.

흔한 오류

데이터 가져오기, 상태 관리, UI를 모두 처리하는 거대한 컴포넌트는 재사용이나 테스트가 어려워집니다. 초기에 분리하세요.

UI 시나리오

뉴스 피드에서:

  • FeedContainer는 API 호출, 페이지네이션, 오류 처리를 담당합니다.
  • FeedItem은 기사만 렌더링합니다.
    데이터‑fetch 로직을 건드리지 않고도 표시 컴포넌트를 교체할 수 있습니다.

베스트 프랙티스

“파일당 하나의 관심사” 접근 방식을 채택합니다:

src/
 ├─ components/
 │   ├─ containers/
 │   └─ presentational/
 └─ hooks/

이 구조는 명확한 경계를 강화하고 재사용성을 높여줍니다.

Back to Blog

관련 글

더 보기 »