Skip to Content
WebReactReact 기초05. 컴포넌트 분리와 props

이번 편의 결과물: BookCard 컴포넌트가 분리되고, App에서 세 권의 책 데이터를 props로 넘겨 카드 3장이 각기 다른 내용으로 보입니다. · 다루는 개념: 컴포넌트로 UI 쪼개기, props로 데이터 전달, 구조 분해 할당, props 불변성

이 편에서 만드는 파일

bookshelf/src/ ├── data/ │ └── books.seed.json (+) ├── components/ │ └── BookCard.jsx (+) └── App.jsx (~)

개념 정리

04편의 App.jsx는 책 한 권의 표지 색·제목·저자를 마크업에 직접 적어 넣은 상태입니다. 책이 여러 권이 되면 같은 마크업을 복사-붙여넣기 해야 하고, 값 하나를 바꾸려면 카드마다 찾아 고쳐야 합니다. 이 문제를 컴포넌트 분리props로 풉니다.

컴포넌트로 쪼갠다는 것

반복되는 마크업 덩어리를 함수 하나로 뽑아내고, 그 함수를 호출(JSX 태그로 사용)할 때마다 다른 데이터를 넘겨 다른 결과를 그리게 합니다. BookCard는 “책 한 권을 카드로 그리는 방법”만 알고, 어떤 책을 그릴지는 몰라도 됩니다.

props란 무엇인가

props는 부모 컴포넌트가 자식 컴포넌트에 넘기는 값입니다. 함수의 매개변수와 같은 자리이며, React는 이 값을 객체 하나로 묶어 전달합니다.

부모 쪽 문법자식 쪽 문법의미
<BookCard title="클린 코드" />function BookCard(props)props.title'클린 코드'
<BookCard title={title} />function BookCard({ title })구조 분해로 바로 title 사용
<BookCard {...book} />function BookCard({ title, author })book 객체의 속성을 한 번에 펼쳐 전달

구조 분해 매개변수({ title, author, coverColor })를 쓰면 props.title처럼 매번 props.를 붙이지 않아도 됩니다. 이 과목의 컴포넌트는 모두 이 방식을 씁니다.

props는 읽기 전용이다

자식 컴포넌트는 전달받은 props를 직접 바꿀 수 없습니다. props.title = '다른 제목'처럼 대입하면 React가 오류를 던지지는 않지만 화면에 반영되지 않고, 다음 렌더링에서 부모가 다시 원래 값을 내려보내 덮어씁니다. 값을 바꾸고 싶다면 그 값을 소유한 컴포넌트의 state를 바꿔야 합니다. state는 08편에서 다룹니다.

실습

1. 시드 데이터 파일 만들기

src/data/books.seed.json을 만들고 아래 내용을 그대로 붙여넣습니다. 이 배열은 앞으로 모든 편에서 책 목록의 출발점으로 씁니다.

2. 코드 작성

// src/data/books.seed.json [ { "id": 1, "title": "클린 코드", "author": "로버트 C. 마틴", "status": "done", "rating": 5, "pages": 584, "coverColor": "#2563eb", "startedAt": "2026-07-01", "finishedAt": "2026-07-20", "memo": "함수는 한 가지 일만." }, { "id": 2, "title": "리팩터링 2판", "author": "마틴 파울러", "status": "reading", "rating": 4, "pages": 550, "coverColor": "#16a34a", "startedAt": "2026-08-10", "finishedAt": null, "memo": "" }, { "id": 3, "title": "모던 자바스크립트 Deep Dive", "author": "이웅모", "status": "done", "rating": 5, "pages": 956, "coverColor": "#f59e0b", "startedAt": "2026-05-01", "finishedAt": "2026-06-15", "memo": "클로저 장이 특히 좋았다." }, { "id": 4, "title": "함께 자라기", "author": "김창준", "status": "wish", "rating": 0, "pages": 224, "coverColor": "#db2777", "startedAt": null, "finishedAt": null, "memo": "" }, { "id": 5, "title": "HTTP 완벽 가이드", "author": "데이빗 고울리 외", "status": "reading", "rating": 3, "pages": 760, "coverColor": "#7c3aed", "startedAt": "2026-09-01", "finishedAt": null, "memo": "" }, { "id": 6, "title": "누구나 자료 구조와 알고리즘", "author": "제이 웬그로우", "status": "done", "rating": 4, "pages": 384, "coverColor": "#0891b2", "startedAt": "2026-03-02", "finishedAt": "2026-03-30", "memo": "" } ]
// src/components/BookCard.jsx function BookCard({ title, author, coverColor, pages }) { return ( <article className="book-card" style={{ borderTop: `6px solid ${coverColor}` }}> <h2>{title}</h2> <p>{author}</p> <p className="book-pages">{pages}쪽</p> </article> ); } export default BookCard;
// src/App.jsx import BookCard from './components/BookCard.jsx'; import books from './data/books.seed.json'; function App() { const [first, second, third] = books; return ( <div className="app"> <h1>내 책장</h1> <div className="book-grid"> <BookCard title={first.title} author={first.author} coverColor={first.coverColor} pages={first.pages} /> <BookCard {...second} /> <BookCard {...third} /> </div> </div> ); } export default App;

first, second, third는 배열 구조 분해로 꺼낸 값입니다. first는 각 props를 하나씩 나열했고, second·third는 스프레드({...second})로 객체의 모든 속성을 한 번에 넘겼습니다. BookCard는 필요한 속성(title, author, coverColor, pages)만 구조 분해로 꺼내 쓰므로, statusrating 같은 나머지 속성이 함께 전달되어도 무시됩니다.

3. 실행

npm run dev

4. 확인

  • 브라우저에서 카드 3장이 보입니다. 각 카드의 제목·저자·쪽수가 다르고, 카드 위쪽 테두리 색이 coverColor 값대로 다릅니다.
  • first 방식과 {...second} 방식으로 만든 카드가 겉보기에 똑같이 렌더링됩니다(전달 방식만 다를 뿐 결과는 같습니다).
  • React DevTools의 Components 탭을 열면(설치는 16편) BookCard가 세 번 나타나고, 각각의 props에 서로 다른 title 값이 보입니다.

직접 해보기

  1. App.jsx에서 네 번째 카드로 <BookCard {...books[3]} />를 추가해봅니다.
  2. BookCard 안에서 title = '변경됨'처럼 매개변수에 직접 대입해보고 어떤 일이 일어나는지 관찰해봅니다(구조 분해로 만든 지역 변수라 오류는 나지만, 왜 이런 시도가 애초에 잘못된 접근인지 “props는 읽기 전용” 절을 다시 읽고 설명해봅니다).

정답 보기

<BookCard {...books[3]} />

title은 구조 분해로 만들어진 지역 상수라 const로 선언된 것과 같습니다. 재대입을 시도하면 Assignment to constant variable 오류가 납니다. 설령 오류가 나지 않는 형태로 바꾸더라도, 그 값은 다음 렌더링에서 부모가 다시 원래 books[3].title을 내려보내며 덮어써집니다. 화면에 보이는 제목을 바꾸려면 books 배열 자체(또는 그 값을 담은 state)를 바꿔야 합니다.

자주 하는 실수

증상원인고치는 법
카드에 undefined가 표시됨props 이름과 구조 분해 이름이 다름(coverColor vs color)<BookCard>에 넘긴 이름과 BookCard({ ... }) 안 이름을 맞춘다
카드 테두리 색이 전혀 안 보임style 객체를 문자열로 넘김(style="border-top: ...")JSX의 style은 반드시 객체(\{\{ borderTop: ... \}\})여야 한다
{...second}를 썼는데 특정 값만 다르게 주고 싶음스프레드 뒤에 개별 prop을 안 겹쳐 씀<BookCard {...second} title="다른 제목" />처럼 스프레드 뒤에 쓰면 뒤의 값이 우선한다

확인 문제

문제 14지선다
컴포넌트를 분리하는 가장 큰 이유로 알맞은 것은?
문제 24지선다
function BookCard({ title, author }) 형태의 매개변수 문법에 대한 설명으로 옳은 것은?
문제 34지선다
BookCard에 스프레드로 book을 펼친 뒤 title을 다른 제목으로 다시 지정해 렌더링하면 title 값은?
문제 44지선다
자식 컴포넌트 안에서 전달받은 props 값을 직접 재대입하면 어떻게 되는가?

참고 자료

Last updated on