* array.map()
Array.prototype.map() - JavaScript | MDN
map() 메서드는 배열 내의 모든 요소 각각에 대하여 주어진 함수를 호출한 결과를 모아 새로운 배열을 반환합니다.
developer.mozilla.org
array.map()메소드는 다른 배열을 기반으로 새로운 배열을 생성하는데, 원본배열에 있는 모든 요소를 변환한다.
map()메소드를 통해 변환 인자를 거쳐 함수가 시행되면 배열에 있는 모든 요소에 map을 실행한다. 이후 새로운 배열이 생성.
<Card className="expenses">
<ExpensesFilter selected={filteredYear} onExpenseFilterData={expenseFilterDataHandler}/>
{props.items.map(expense => (
<ExpenseItem
title={expense.title}
amount={expense.amount}
date={expense.date}/>
))}
</Card>
//array.map(사용자가 지정한 매개변수명 => <사용자지정 컴포넌트 />)
사용자 지정 컴포넌트를 동적으로 할당하기 위해서 map메서드를 이용한다.
map을 이용해서 컴포넌트에 props로 받아온 items 배열을 할당할 수 있다.
+) key를 부여하기
리액트는 새로운 아이템이 추가 되었을 때 어디에 추가해야하는지 모른다.
그래서 배열에 추가할 때, 가장 마지막에 추가한 다음 배열을 사용자가 설정해놓은 대로 재배열하는 과정을 거치게 된다.
이는 리액트가 어떤 배열을 어디에 추가해야하는지, 어떤 배열이 우선에 있는지 모르기 때문에 발생하는 현상이다.
해결하기 위해서는 사용자 지정 컴포넌트에 고유한 값 key를 부여하면 해결할 수 있다.
여기서 key는 고유한 문자열, 숫자 등 무엇이든 될 수 있다.
> key를 부여하면, 배열의 길이와 배열의 존재해야할 위치 모두를 인식한다.
즉, 목록을 매핑할때면 항상 key를 추가해야한다.
Array.prototype.filter() - JavaScript | MDN
filter() 메서드는 주어진 함수의 테스트를 통과하는 모든 요소를 모아 새로운 배열로 반환합니다.
developer.mozilla.org
드롭다운에서 연도를 선택시, 해당 연도의 아이템만 리스트업 하고 싶을 때, filter를 사용한다.
const filteredExpenses (새로운 배열)
= props.items.filter (props의 item배열에 filter()적용)
(expense (사용자가 지정한 임의의 매개변수명(props.items의 배열 하나하나씩))
=> {return expense.date.getFullYear().toString() === filteredYear; });
import React, { useState } from "react";
import ExpenseItem from "./ExpenseItem";
import Card from "../UI/Card";
import ExpensesFilter from "./ExpensesFilter";
import "./Expenses.css";
function Expenses(props){
//양방향 바인딩을 통해 드롭다운의 기본 년도를 설정할 수 있다.
//filteredYear를 사용자지정컴포넌트에 selected={filteredYear}로 전달하면,
//사용자지정컴포넌트 내부에서 props.selected로 접근할 수 있고,
//dropdown에서 value값을 지정해주면 그 값으로 기본값을 지정해줄 수 있다.
const [filteredYear, setFilteredYear] = useState('2020');
//필터를 통해 년도별 아이템 목록을 출력하고 싶음.
//filter()메소드를 사용해서 배열의.date.getFullYear().toString()으로 년도만 가져온 뒤,
//가져온 연도와 필터링된연도가 같으면 filteredExpenses배열에 남겨두는 것.
//filteredExpenses배열은 우리가 매핑하고 싶은 배열이기 때문에
//(32번째 줄)props.item.map 에서 filteredExpenses.map으로 변경해준다.
const filteredExpenses = props.items.filter(expense => {
return expense.date.getFullYear().toString() === filteredYear;
});
const expenseFilterDataHandler = (selectedYear) => {
setFilteredYear(selectedYear);
};
return(
<Card className="expenses">
<ExpensesFilter
selected={filteredYear}
onExpenseFilterData={expenseFilterDataHandler}
/>
{filteredExpenses.length === 0 ? <p>No expenses found</p> :
filteredExpenses.map(expense => (
<ExpenseItem
key={expense.id}
title={expense.title}
amount={expense.amount}
date={expense.date}
/>
))}
</Card>
)
}
export default Expenses;
+) 필터는 조건부로 렌더링할 때에도 사용될 수 있는데,
중괄호 안에는 for문이나 if문처럼 긴 조건문이 들어갈 수 없기 때문에 삼항연산자를 사용해야한다.
{조건문 ? 조건문이 참일 시 실행할 표현식 : 조건문이 거짓일 시 실행할 표현식}
표현식 안에 JSX 사용이 가능하다.
조건 (삼항) 연산자 - JavaScript | MDN
조건 (삼항) 연산자는 JavaScript에서 세 개의 피연산자를 받는 유일한 연산자입니다. 앞에서부터 조건문, 물음표(?), 조건문이 참(truthy)일 경우 실행할 표현식, 콜론(:), 조건문이 거짓(falsy)일 경우
developer.mozilla.org
Q) 그렇다면 꼭 삼항연산자를 사용해야 할까? 놉
{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}
/>
))}
&& 연산자를 사용해서 삼항연산자 말고 2개의 조건문으로 구분할 수 있다.
{ 조건 && 조건이 참일 시 실행할 표현식 }
직접적으로 return 문 내부에 조건을 통해 적어넣어도 되지만, 너무 길다 싶다.
let expensesContent = <p>No Expenses Found</p>;
if(filteredExpenses.length > 0 ){
expensesContent = filteredExpenses.map(expense => (
<ExpenseItem
key={expense.id}
title={expense.title}
amount={expense.amount}
date={expense.date}
/>
))
}
return(
<Card className="expenses">
<ExpensesFilter
selected={filteredYear}
onExpenseFilterData={expenseFilterDataHandler}
/>
{expensesContent}
</Card>
)
}
return 밖에서 조건문을 거친 다음, 내부에서 렌더링해주는 방법도 있다.
어느쪽을 사용하든 상관 없으나, 이 편이 코드가 간결하다.