React의 기본 데이터 흐름은 하향식(Top-Down)입니다 (부모 → 자식, via Props). 하지만 자식 컴포넌트에서 발생한 데이터를 부모 컴포넌트로 전달해야 할 때가 많습니다. (e.g., 자식의 폼에서 입력한 데이터를 부모의 목록 상태에 추가)
핵심 원리: 부모가 데이터를 처리할 함수를 자식에게 Props로 전달하고, 자식은 그 함수를 호출하여 데이터를 "위로" 보냅니다.
[부모] 자식으로부터 받은 데이터를 처리할 함수를 정의합니다.
[부모] 해당 함수를 자식 컴포넌트에 Props로 전달합니다. (e.g., onSaveData={...})
[자식] 특정 이벤트(e.g., 폼 제출)가 발생했을 때, Props로 전달받은 함수를 호출하면서 전달할 데이터를 인자로 넘깁니다.
[부모] 함수가 호출되면서 자식의 데이터가 부모의 상태를 업데이트하고, 리렌더링이 발생합니다.
// 부모 컴포넌트: App.js
function App() {
const [expenses, setExpenses] = useState([]);
// 1. 자식의 데이터를 받아 처리할 함수
const addExpenseHandler = (expenseData) => {
setExpenses((prevExpenses) => [expenseData, ...prevExpenses]);
};
return (
<div>
{/* 2. 자식에게 함수를 props로 전달 */}
<NewExpenseForm onAddExpense={addExpenseHandler} />
<ExpenseList items={expenses} />
</div>
);
}
// 자식 컴포넌트: NewExpenseForm.js
function NewExpenseForm(props) {
const submitHandler = (event) => {
event.preventDefault();
const newExpense = { /* ... 폼 데이터 ... */ };
// 3. props로 받은 함수를 호출하여 데이터를 위로 전달
props.onAddExpense(newExpense);
};
return <form onSubmit={submitHandler}>...</form>;
}
map() 메서드를 사용합니다. map()은 배열의 각 요소를 순회하며, 각 요소를 JSX 엘리먼트로 변환한 새로운 배열을 반환합니다.key Prop의 중요성map()을 사용하여 리스트를 렌더링할 때는, 각 엘리먼트에 key라는 특별한 Prop을 반드시 포함해야 합니다.
key의 역할: React가 리스트의 항목이 변경, 추가, 또는 삭제되었을 때 어떤 항목을 변경해야 하는지 효율적으로 식별하기 위해 사용됩니다. key는 React에게 각 항목의 "신분증"과 같습니다.
좋은 key: 각 항목을 고유하게 식별할 수 있는 안정적인 값이어야 합니다. (e.g., 데이터의 id) 배열의 인덱스는 데이터가 변경되지 않는 정적인 리스트에서만 최후의 수단으로 사용해야 합니다.
function ExpenseList(props) {
return (
<ul>
{/* 배열(props.items)을 map으로 순회하며 ExpenseItem 컴포넌트 렌더링 */}
{props.items.map((expense) => (
<ExpenseItem
key={expense.id} // 각 항목을 식별할 고유하고 안정적인 key
title={expense.title}
amount={expense.amount}
/>
))}
</ul>
);
}
| 방법 | 사용 사례 | 예시 코드 |
|---|---|---|
| 삼항 연산자 | if-else와 같이 두 가지 경우 중 하나를 렌더링할 때 | {isEditing ? <EditForm /> : <DisplayView />} |
논리 && 연산자 | 특정 조건이 참일 때만 엘리먼트를 렌더링할 때 | {isLoggedIn && <UserProfile />} |
if문과 변수 | 렌더링 로직이 복잡하여 JSX 밖에서 처리해야 할 때 | let content = <p>No items found.</p>;if (items.length > 0) { ... }return <div>{content}</div>; |
function ExpenseList(props) {
// if문과 변수를 사용한 조건부 렌더링
if (props.items.length === 0) {
return <h2 className="expenses-list__fallback">Found no expenses.</h2>;
}
return (
<ul className="expenses-list">
{props.items.map((expense) => (
<ExpenseItem
key={expense.id}
title={expense.title}
amount={expense.amount}
/>
))}
</ul>
);
}
map() 메서드를 사용하며, 각 항목에는 반드시 고유한 key Prop을 지정하여 렌더링 효율을 높여야 합니다.&& 연산자, if문 등 다양한 조건부 렌더링 기법을 활용합니다.