이전에 component를 조금 살펴봤는데 이번에는 간단한 프로젝트를 만들어보면서 더 자세히 알아보고자 한다.
간단히 말하면 컴포넌트란 html을 반환하는 자바스크립트 함수라고 할 수 있다.
컴포넌트는 보통 기능이나 단위에 따라 각각의 파일로 분류를 하는데 이때 몇가지 규칙을 갖는다.
위 규칙으로 파일명(함수명)을 만들면 ExpenseItem 과 같이 만들 수 있다.
expense + item 두 단어를 합쳐서 만들었고, 함수명만 보고도 어떤 상품의 가격을 나타내는 기능을 하는구나 라고 추측을 할 수 있다.
function App() {
return (
<div>
<h2>Let's get started!</h2>
<div>This is React</div>
<ExpenseItem />
</div>
);
}
이렇게 만들어진 컴포넌트는 위와같이 사용할 수 있다. 그런데 여기서도 약간의 규칙이 존재한다.
<div>, <h2> 같은 내장된 html은 소문자로 시작한다.return 바로 하위에 있는 <div> 태그가 안에 있는 태그들을 감싸고 있는것이 보일 것 이다. 이처럼 반환되는 루트 요소는 1개만 가능하다.
컴포넌트들은 각각의 파일로 이루어져 있는데, A라는 파일에서 B라는 컴포넌트를 사용하고 싶을 수 있다. 이럴 때 사용하는 것이 export & import 이다.
먼저 내가 내보내고 싶은 컴포넌트 앞에 export를 사용한 뒤, 내보낸 컴포넌트를 사용하고 싶은 파일에서 import하면 컴포넌트를 사용할 수 있게 된다.
// componets/ExpenseItem.js
import "./ExpenseItem.css";
export default function ExpenseItem() {
return (
<div className="expense-item">
<div>March 28th 2021</div>
<div className="expense-item__description">
<h2>Car Insurance</h2>
<div className="expense-item__price">$294.97</div>
</div>
</div>
);
}
// App.js
import ExpenseItem from "./components/ExpenseItem";
function App() {
return (
<div>
<h2>Let's get started!</h2>
<ExpenseItem />
</div>
);
}
export default App;
export된 ExpenseItem를 App.js에서 import하여 컴포넌트로 사용하였다.
props는 읽기 전용으로, 상위 컴포넌트에서 하위 컴포넌트에 값을 전달하기 위해 사용한다.

현재 작성한 컴포넌트들의 구조와 props는 위와 같이 이루어져 있다.
아래 코드를 통해 더 살펴보자.
// App.js
import Expenses from "./components/Expenses";
function App() {
const expenses = [
{
id: "e1",
title: "Toilet Paper",
amount: 94.12,
date: new Date(2020, 7, 14),
},
{ id: "e2",
title: "New TV",
amount: 799.49,
date: new Date(2021, 2, 12) },
{
id: "e3",
title: "Car Insurance",
amount: 294.67,
date: new Date(2021, 2, 28),
},
{
id: "e4",
title: "New Desk (Wooden)",
amount: 450,
date: new Date(2021, 5, 12),
},
];
return (
<div>
<h2>Let's get started!</h2>
<Expenses items={expenses} />
</div>
);
}
// components/ExpenseDate.js
import "./ExpenseDate.css";
export default function ExpenseDate(props) {
const month = props.date.toLocaleString("en-US", { month: "long" });
const day = props.date.toLocaleString("en-US", { day: "2-digit" });
const year = props.date.getFullYear();
return (
<div className="expense-date">
<div className="expense-date__month">{month}</div>
<div className="expense-date__year">{year}</div>
<div className="expense-date__day">{day}</div>
</div>
);
}
App.js 부터 받은 data를 props를 통해 전달 받아 ExpenseDate에서 사용하였다.
이렇게 props를 사용하면 아래와 같은 장점을 갖는다.
컴포넌트들을 감싸는 컴포넌트
Expneses 와 ExpenseItem 에서 공통으로 갖는 CSS 스타일을 분리하여 Card 컴포넌트를 만들었다.
// components/Card.js
import "./Card.css";
export default function Card(props) {
const classes = "card " + props.className;
return <div className={classes}>{props.children}</div>;
}
/* cmponents/Card.css */
.card {
border-radius: 12px;
box-shadow: 0 1px 8px rgba(0, 0, 0, 0.25);
}
Expneses, ExpenseItem 에서도 갖는 스타일이 있기 때문에 card스타일과 함께 적용될 수 있도록 classes를 선언한 뒤 className에 넣어주었다.
{props.children} 은 Card 태그 사이에 오는 컴포넌트들을 보여주기 위해 사용하는 props이다.
이렇게 만들어진 wrapper component 는 아래 코드와 같이 사용되었다.
// components/ExpenseItem.js
import "./ExpenseItem.css";
import ExpenseDate from "./ExpenseDate";
import Card from "./Card";
export default function ExpenseItem(props) {
return (
<Card className="expense-item">
<ExpenseDate date={props.date} />
<div className="expense-item__description">
<h2>{props.title}</h2>
<div className="expense-item__price">${props.amount}</div>
</div>
</Card>
);
}
// components/Expenses.js
import ExpenseItem from "./ExpenseItem";
import Card from "./Card";
import "./Expenses.css";
export default function Expenses(props) {
return (
<Card className="expenses">
<ExpenseItem
title={props.items[0].title}
amount={props.items[0].amount}
date={props.items[0].date}
/>
.
.
.
</Card>
);
}
