Notice
Recent Posts
Recent Comments
Link
JiSoo's Devlog
[Udemy React 완벽 가이드] Section 5 본문
데이터의 렌더링 목록
- App.js에서 정의된 expenses를 렌더링
- Expenses 배열인 데이터 배열에 접근해서 모든 배열 요소에 대해 JSX 요소를 생성한다
- map 메소드는 다른 배열을 기반으로 새로운 배열을 생성하는데 원본 배열에 있는 모든 요소들을 변환한다
- 함수의 결괏값은 새로 생성될 배열에 추가될 요소이다
- map은 매개변수로 함수를 취하고 그 함수는 배열에 있는 모든 요소를 실행해서 현재 매개변수로 실행되고 있는 요소를 얻는다
{props.items.map(expense => ( //함수의 오른쪽 부분에는 이 expense를 매핑할 JSX요소를 반환해야 한다
<ExpenseItem
title={expense.title} //expense는 title를 추출하는데 사용된다
amount={expense.amount}
date={expense.date}
/>
))}
- expense 객체를 특별한 객체, JSX 요소로 변환
- expense는 자동적으로 함수를 매개변수로 전달하는 게 그게 바로 map이 작동하는 방식이기 때문이고 expense는 title를 추출하는 데 사용된다
- 배열을 JSX 아이템들로 가득 찬 배열로 변환해 주는 map 표현식만 남긴다
Expenses.js
return (
<div>
<Card className="expenses">
<ExpensesFilter
selected={filteredYear}
onChangeFilter={filterChangeHandler}
/>
{props.items.map((expense) => (
<ExpenseItem
title={expense.title}
amount={expense.amount}
date={expense.date}
/>
))}
</Card>
</div>
);
};
데이터 목록 렌더링 하기
- 더미 할 일 항목의 목록을 동적으로 출력
App.js
import React from 'react';
import Todo from './Todo';
import './styles.css';
const DUMMY_TODOS = [
'Learn React',
'Practice React',
'Profit!'
];
// don't change the Component name "App"
export default function App() {
return (
<ul>
{DUMMY_TODOS.map(todo=> <Todo text={todo}/>)}
</ul>
);
}
Todo.js
import React from 'react';
export default function Todo(props) {
return <li>{props.text}</li>;
}
State 저장 목록 사용
- 스프레드 연산자는 객체뿐만 아니라 배열에도 사용 가능
App.js
import React, { useState } from "react";
import NewExpense from "./components/NewExpense/NewExpense";
import Expenses from "./components/Expenses/Expenses";
const DUMMY_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),
},
];
const App = () => {
const [expenses, setExpenses] = useState(DUMMY_EXPENSES);
const addExpenseHandler = (expense) => { //이 함수는 새로운 expense가 추가될 때마다 작동
setExpenses((prevExpenses) => {
return [expense, ...prevExpenses];
//리액트에 의해 자동으로 이전 expenses를 얻게 되고 여기서 매개변수로 얻는 이 expense를 추가하는 새 배열을
반환하고 스프레드 연산자와 함께 이전 expenses를 추가한다
});
};
// return React.createElement(
// 'div',
// {},
// React.createElement('h2', {}, "Let's get started!"),
// React.createElement(Expenses, { items: expenses })
// );
return (
<div>
<NewExpense onAddExpense={addExpenseHandler} />
<Expenses items={expenses} />
</div>
);
};
export default App;
- 배열의 상수 expenses를 가지고 컴포넌트 함수 밖에서 추출하고 App 컴포넌트 함수에서 useState를 호출해 DUMMY EXPENSES를 전달할 수 있다
- 이 배열은 연습용 데이터로 가득 찬 초기 상태 값을 가지면서 화면에 표시할 수 있는 초기 expense를 갖는다
- 동일한 상태의 이전 스냅샷을 기반으로 하는 경우에 우리의 상태를 업데이트할 수 있는 깔끔한 방법
"key" 이해하기
- key props는 ExpenseItem 안에서 사용하는 것이 아니지만 props 대신 어떤 컴포넌트에도 추가할 수 있다
- 고유한 id가 있다면 그걸로 설정해 주면 되겠지만 없다면 두 번째 인자 설정해 주면 되는데 이는 map에 전달하는 함수에서 자동으로 얻어지는 것으로 그 함수는 자동으로 인덱스를 관리해 준다
- 하지만 특정한 아이템에 대한 인덱스가 항상 똑같고 아이템 콘텐츠에 직접적으로 첨부된 것이 아니기 때문에 좋은 방법은 아니다
- 특정 컨텐츠를 갖는 모든 아이템들은 분명하게 고유한 id를 갖고 있어야 한
- 어떤 원시 값도 고유 식별자로 사용할 수 있고 어떤 숫자나 문자열도 고유 식별자가 될 수 있다
{props.items.map((expense) => (
<ExpenseItem
key={expense.id}
title={expense.title}
amount={expense.amount}
date={expense.date}
/>
))}
- 목록의 아이템을 매핑할 때는 항상 key를 추가해야 한다
목록 작업하기
Expenses.js
import React, { useState } from "react";
import ExpenseItem from "./ExpenseItem";
import Card from "../UI/Card";
import ExpensesFilter from "./ExpensesFilter";
import "./Expenses.css";
const Expenses = (props) => {
const [filteredYear, setFilteredYear] = useState("2020");
const filterChangeHandler = (selectedYear) => {
setFilteredYear(selectedYear);
};
const filteredExpenses = props.items.filter((expense) => {
return expense.date.getFullYear().toString() === filteredYear;
});
return (
<div>
<Card className="expenses">
<ExpensesFilter
selected={filteredYear}
onChangeFilter={filterChangeHandler}
/>
{filteredExpenses.map((expense) => (
<ExpenseItem
key={expense.id}
title={expense.title}
amount={expense.amount}
date={expense.date}
/>
))}
</Card>
</div>
);
};
export default Expenses;
조건부 내용 출력하기
- 조건부 콘텐츠는 각각 다른 상황에서 다양한 출력값을 렌더링 하는 것
{filteredExpenses.length === 0 ? (
<p>No expenses found.</p>
) : (
filteredExpenses.map((expense) => (
<ExpenseItem
key={expense.id}
title={expense.title}
amount={expense.amount}
date={expense.date}
/>
))
)}
{filteredExpenses.length === 0 && <p>No expenses found.</p>}
{filteredExpenses.length > 0 && //자바스크립트는 && 연산자를 사용하도록 동작
filteredExpenses.map((expense) => (
<ExpenseItem
key={expense.id}
title={expense.title}
amount={expense.amount}
date={expense.date}
/>
))}
let expenseContent = <p>No expenses found.</p> //변수에 기본값 할당
if(filteredExpenses.length >0){
expenseContent = filteredExpenses.map((expense) => (
<ExpenseItem
key={expense.id}
title={expense.title}
amount={expense.amount}
date={expense.date}
/>
))
}
조건에 따라 콘텐츠 출력하기
- 버튼 클릭하면 경고 상자 표시
import React from 'react';
export default function App() {
const [btnClick, setBtnClick] = React.useState(false);
let btn;
if(btnClick){
btn = (<div id="alert">
<h2>Are you sure?</h2>
<p>These changes can't be reverted!</p>
<button onClick={()=>setBtnClick(false)}>Proceed</button>
</div>)
}
return (
<div>
{btn}
<button onClick={()=>{
setBtnClick(!btnClick);
}} >Delete</button>
</div>
);
}
조건 명령문 반환 추가하기
- 또 다른 컴포넌트의 도움으로 렌더링을 위한 별개의 로직을 사용하고 다른 JSX 코드를 반환할 수 있다
ExpensesList.js
import React from "react";
import ExpenseItem from "./ExpenseItem";
import "./ExpensesList.css";
const ExpensesList = (props) => {
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}
date={expense.date}
/>
))}
</ul>
);
};
export default ExpensesList;
조건 명령문 반환 추가하기
NewExpense.js
import React, { useState } from "react";
import "./NewExpense.css";
import ExpenseForm from "./ExpenseForm";
const NewExpense = (props) => {
const [isEditing, setIsEditing] = useState(false);
const saveExpenseDataHandler = (enteredExpenseData) => {
const expenseData = {
...enteredExpenseData,
id: Math.random().toString(),
};
props.onAddExpense(expenseData);
setIsEditing(false);
};
const startEditingHandler = () => {
setIsEditing(true);
};
const stopEditingHandler = () => {
setIsEditing(false);
};
return (
<div className="new-expense">
{!isEditing && (
<button onClick={startEditingHandler}>And New Expense</button>
)}
{isEditing && (
<ExpenseForm
onSaveExpenseData={saveExpenseDataHandler}
onCancel={stopEditingHandler}
/>
)}
</div>
);
};
export default NewExpense;
ExpenseForm.js
import React, { useState } from "react";
import "./ExpenseForm.css";
const ExpenseForm = (props) => {
const [enteredTitle, setEnteredTitle] = useState("");
const [enteredAmount, setEnteredAmount] = useState("");
const [enteredDate, setEnteredDate] = useState("");
// const [userInput, setUserInput] = useState({
// enteredTitle: '',
// enteredAmount: '',
// enteredDate: '',
// });
const titleChangeHandler = (event) => {
setEnteredTitle(event.target.value);
// setUserInput({
// ...userInput,
// enteredTitle: event.target.value,
// });
// setUserInput((prevState) => {
// return { ...prevState, enteredTitle: event.target.value };
// });
};
const amountChangeHandler = (event) => {
setEnteredAmount(event.target.value);
// setUserInput({
// ...userInput,
// enteredAmount: event.target.value,
// });
};
const dateChangeHandler = (event) => {
setEnteredDate(event.target.value);
// setUserInput({
// ...userInput,
// enteredDate: event.target.value,
// });
};
const submitHandler = (event) => {
event.preventDefault();
const expenseData = {
title: enteredTitle,
amount: enteredAmount,
date: new Date(enteredDate),
};
props.onSaveExpenseData(expenseData);
setEnteredTitle("");
setEnteredAmount("");
setEnteredDate("");
};
return (
<form onSubmit={submitHandler}>
<div className="new-expense__controls">
<div className="new-expense__control">
<label>Title</label>
<input
type="text"
value={enteredTitle}
onChange={titleChangeHandler}
/>
</div>
<div className="new-expense__control">
<label>Amount</label>
<input
type="number"
min="0.01"
step="0.01"
value={enteredAmount}
onChange={amountChangeHandler}
/>
</div>
<div className="new-expense__control">
<label>Date</label>
<input
type="date"
min="2019-01-01"
max="2022-12-31"
value={enteredDate}
onChange={dateChangeHandler}
/>
</div>
</div>
<div className="new-expense__actions">
<button type="button" onClick={props.onCancel}>
Cancel
</button>
<button type="submit">Add Expense</button>
</div>
</form>
);
};
export default ExpenseForm;
차트 추가하기
- 데이터 포인터를 통해 차트 바가 동적으로 출력되도록 하고 모든 데이터 포인트를 차트 바에 매핑할 것이다
- 모든 차트의 바는 전체 차트의 최댓값을 기준으로 값을 표시한다
Chart.js
import React from "react";
import ChartBar from "./ChartBar";
import "./Chart.css";
const Chart = (props) => {
return (
<div className="chart">
{props.dataPoints.map((dataPoint) => (
<ChartBar
key={dataPoint.label}
value={dataPoint.value}
maxValue={null}
label={dataPoint.label}
/>
))}
</div>
);
};
export default Chart;
동적 스타일 추가하기
- style 속성을 리액트로 응용프로그램을 구축할 때 약간 다르게 동작한다
- 최댓값을 기준으로 값을 넣어 차트의 바를 채우고 싶다
CharBar.js
import React from "react";
import "./ChartBar.css";
const ChartBar = (props) => {
let barFillHeight = "0%"; //초깃값
if (props.maxValue > 0) {
barFillHeight = Math.round((props.value / props.maxValue) * 100) + "%";
}
return (
<div className="chart-bar">
<div className="chart-bar__inner">
<div
className="chart-bar__fill"
style={{ height: barFillHeight }} //style의 값으로 자바스크립트를 사용해야 한다
></div>
</div>
<div className="chart-bar__label">{props.label}</div>
</div>
);
};
export default ChartBar;
Char.js
import React from "react";
import ChartBar from "./ChartBar";
import "./Chart.css";
const Chart = (props) => {
const dataPointValues = props.dataPoints.map((dataPoint) => dataPoint.value);
const totalMaximum = Math.max(...dataPointValues);
return (
<div className="chart">
{props.dataPoints.map((dataPoint) => (
<ChartBar
key={dataPoint.label}
value={dataPoint.value}
maxValue={totalMaximum}
label={dataPoint.label}
/>
))}
</div>
);
};
export default Chart;
퀴즈
someArray.map((element) => <p>{element}</p>)
이 코드 예시는 어떤 작업을 수행하나요?
- 배열을 React에서 출력 가능한 JSX 요소로 채워진 새 배열로 변환한다(someArray)
JSX 요소를 나열할 때 왜 특수한 "키" 프로퍼티를 추가해야 하나요?
- React가 목록 요소를 올바르게 식별 및 업데이트(필요시) 하는 데 필요하기 때문이다
React 컴포넌트에서 조건부 콘텐츠를 출력하는 데 관한 설명으로 옳은 것은 무엇인가요?
- 컴포넌트에서 다른 결과를 출력 또는 반환하기 위해 if 검사의 정규 삼항 표현식으로 작업할 수 있다
728x90
'Frontend > React' 카테고리의 다른 글
[Udemy React 완벽 가이드] Section 7 (1) | 2024.01.04 |
---|---|
[Udemy React 완벽 가이드] Section 6 (2) | 2024.01.04 |
[Udemy React 완벽 가이드] Section 4 (2) | 2024.01.04 |
[Udemy React 완벽 가이드] Section 3 (1) | 2024.01.04 |
[Udemy React 완벽 가이드] Section 2 (3) | 2024.01.04 |