표준 예제
//Expenses.js
import ExpenseItem from "./ExpenseItem";
import "./Expenses.css";
function Expenses(props) {
return (
<div className="expenses">
<ExpenseItem
title={props.items[0].title}
amount={props.items[0].amount}
date={props.items[0].date}
/>
<ExpenseItem
title={props.items[1].title}
amount={props.items[1].amount}
date={props.items[1].date}
/>
<ExpenseItem
title={props.items[2].title}
amount={props.items[2].amount}
date={props.items[2].date}
/>
<ExpenseItem
title={props.items[3].title}
amount={props.items[3].amount}
date={props.items[3].date}
/>
</div>
);
}
export default Expenses;
// ExpenseItem.js
import ExpenseDate from "./ExpenseDate";
import "./ExpenseItem.css";
function ExpenseItem(props) {
return (
<div 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>
</div>
);
}
export default ExpenseItem;
작은 빌딩 블럭으로부터 사용자 인터페이스를 구축하는. 이런 접근 방법을 일반적으로 composition(합성)이라 부릅니다
우리가 지금까지 본 적 없는 컴포넌트가 가진 흥미로운 면이 있는데요
만약 이미 다른 컨텐츠 주변에서 셸 역할을 하는 컴포넌트를 생성하고 싶다면 어떨까요?
현재 출력을 보면 두 종류의박스나 컨테이너를 볼 수 있습니다 모든 비용 아이템들 주변에는 컨테이너가 있습니다.
회색 바탕에 모서리가 둥글고 옅은 그림자가 있는 상자입니다. 그리고 전체 비용 목록 주변에 컨테이너가 있습니다 둥근 모서리에 옅은 그림자가 있습니다. 이런 모든 컴포넌트의 뒷단에 있는 아이디어는 재사용가능한 빌딩 블럭을 갖는 것이고 또한 코드 중복을 피하는 것입니다
지금 여기에서는 몇몇 스타일을 중복하고 일부 Html 구조도 중복하고 있습니다
Expenses 클래스는 <div>태그를 갖고 있어서 특정 스타일을 적용하는 비용들을 감싸고 있습니다
ExpenseItem도 마찬가지입니다. 물론 모든 <div>태그가 같은 모양을 갖는 것은 아닙니다. ExpenseItem안쪽에도 <div>가 있는데요 완전히 다른 모양입니다 .그럼에도 불구하고, ExpenseItem.js와 Expenses.js 파일에서 모두 갖고 있는 컨테이너 <div>과 공동으로 갖고 있는 스타일을 추출할 수 있습니다
예를 들면, 둥근 모서리나 그림자같은 스타일을 별도의 컴포넌트로 만듭니다.
<감싼 예제>
.card{
border-radius: 12px;
box-shadow: 0 1px 8px rgba(0, 0, 0, 0.25);
}
//Card.js
import "./Card.css";
function Card(props) {
const classes = "card " + props.className;
// children : [<ExpenseItem />, <ExpenseItem />, <ExpenseItem />,…]
return <div className={classes}>{props.children}</div>;
}
export default Card;
//Expenses.js
import Card from "../UI/Card/Card";
import ExpenseItem from "./ExpenseItem";
import "./Expenses.css";
function Expenses(props) {
return (
<Card className="expenses">
<ExpenseItem
title={props.items[0].title}
amount={props.items[0].amount}
date={props.items[0].date}
/>
<ExpenseItem
title={props.items[1].title}
amount={props.items[1].amount}
date={props.items[1].date}
/>
<ExpenseItem
title={props.items[2].title}
amount={props.items[2].amount}
date={props.items[2].date}
/>
<ExpenseItem
title={props.items[3].title}
amount={props.items[3].amount}
date={props.items[3].date}
/>
</Card>
);
}
export default Expenses;
//ExpenseItem.js
import Card from "../UI/Card/Card";
import ExpenseDate from "./ExpenseDate";
import "./ExpenseItem.css";
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>
);
}
export default ExpenseItem;
{props.children}을 설정해 주지 않으면 모든 아이 템들이 사라지는데 상자 밖에 있기 때문입니다.
사용자 지정 컴포넌트를 일종의 컨텐츠를 감싸는 wrapper를 사용할 수 없기 때문입니다.
왜 이렇게 설정 했나?
const classes = "card " + props.className;
return <div className={classes}>{props.children}</div>;
❌ return <div className='card'>{props.children}</div>;
사용자 정의 컴포넌트들은 지원하라고 지시한 것만 지원합니다. 그래서 classname을 card만 설정 해 준 경우,
이런식으로 기존 css설정해 준것이 무너 질 수 있습니다.
해결하기 위해서 card는 default class로 설정하고 추가로 밖에서 className을 받는 것들을 문자열로 설정해 줍니다.
'React' 카테고리의 다른 글
리액트 라우터 outlet 사용하여 중첩된 레이아웃 구성 (0) | 2023.03.09 |
---|---|
Custom Hook 만들기 (0) | 2023.03.01 |
useState & useEffect 비교 (0) | 2023.03.01 |
React Portal이란? (0) | 2023.03.01 |
DOM(돔) vs Virtual DOM(가상 돔) (0) | 2023.02.14 |