
들어가기전 JavaSciprt 복습
Map 메서드 : 자신이 호출한 배열의 모든 요소를 차례대로 순회하며 인수로 전달받은 콜백함수를 반복 호출한다. 그리고 콜백 함수의 반환값들로 구성된 새로운 배열을 반환한다.
const people = [
{
id : 1,
name : "kim"
},
{
id : 2,
name : "seung"
},
{
id : 3,
name : "seung2"
}
];
const newPeople = people.map( (콜백함수) => { return { newId : 콜백함수.id ,newName : 콜백함수.name} } );
// 첫번째 콜백함수가 실행될때 요소는 map을 호출한 people 배열에서 0번째 인덱스인 객체 요소를 얻는다.
// 두번째 콜백함수가 실행될때 요소는 map을 호출한 people 배열에서 1번째 인덱스인 객체 요소를 얻는다.
// 세번째 콜백함수가 실행될때 요소는 map을 호출한 people 배열에서 2번째 인덱스인 객체 요소를 얻는다.
console.log(newPeople);
// result
/*
[
{ newId: 1, newName: 'kim' },
{ newId: 2, newName: 'seung' },
{ newId: 3, newName: 'seung2' }
]
*/
People.js
<PeopleItem
name = {props.item[0].name}
age = {props.item[0].age}
weight = {props.item[0].weight}
home = {props.item[0].home}
/>
<PeopleItem
name = {props.item[1].name}
age = {props.item[1].age}
weight = {props.item[1].weight}
home = {props.item[1].home}
/>
<PeopleItem
name = {props.item[2].name}
age = {props.item[2].age}
weight = {props.item[2].weight}
home = {props.item[2].home}
/>
<PeopleItem
name = {props.item[3].name}
age = {props.item[3].age}
weight = {props.item[3].weight}
home = {props.item[3].home}
/>
( 위 코드는 App.js 에서 item 프로퍼티로 props를 통해 데이터를 전달받고있다는 점을 알아두자... )
이 코드들은 동적이지가 않다. 웹페이제에서 어떠한 인풋요소가 들어와도 웹페이지의 변경사항은 없다.
그렇다면 저 코드들을 바꿔서 데이터가 들어와도 동적으로 추가하게끔 하는 방법은 무엇일까?
배열을 받는다면 map 메서드를 이용하자!
People.js
{props.item.map((callback) => (
<PeopleItem
name={callback.item}
age={callback.age}
weight={callback.age}
home={callback.home}
/>
))}
목록들로 배열을 받았다면 App.js 에서 최종적으로 업데이트를 어떻게 시켜주어야할까?
당연하게도 업데이트를 해야하니 상태를 관리하는 useState를 써야할 것이다.
일반 변수로 관리를 한다면 리액트는 컴포넌트를 업데이트하지 않는다.
const DUMMY_PEOPLE = [
// 상수로 따로 빼주자.
... // 생략 , 많은 데이터들이 담겨있다
]
const App = () => {
const [ people, setPeople ] = useState(DUMMY_PEOPLE);
// 들어오는 데이터를 enteredPeople이라는 인자로 명명할게요.
// ( 함수실행은 자식 컴포넌트에서 실행하는데, 실행할때 인자를 이용하여 데이터를 넘긴다.
// 그 데이터를 이 인자로 이용한다. )
// 자식 컴포넌트에서 보낼때 인자이름과 부모 컴포넌트에서 받을때 인자이름은 달라도된다.
const onAddPeopleDataHandler = (enteredPeople) => {
// 배웠던 부분이지만 중요하다. 이 문법을 잘 기억해두자.
// setPeople같은 상대 업데이트 함수는 >>자동<<으로 최신 상태의 스냅샷을 받는다.
// 이 코드에서는 prevPeople 이라는 인자로 최신 상태의 스냅샷을 받았다.
// 리턴 값을 해석하자면 [ 들어온 새로운 데이터 , ... 최신 상태의 스냅샷 모두 ]
setPeople( (prevPeople) => {
return [enteredPeople, ...prevPeople];
});
};
return (
<div>
<NewPeople onAddPeopleData={onAddPeopleDataHandler} />
</div>
);
};
export default App;
실행결과 :
인풋값에 따른 목록추가가 이루어진것을 볼 수 있다.
지금까지 배운것을 적용하면 작동은 잘 된다. 하지만 콘솔창을 보면 오류메시지가 나온다. 왜냐하면 리액트는 새로 추가된 인풋값이 어디에 추가되어야 하는지 모르기 때문이다.
해결 방법 => 모든 컴포넌트에서도 사용할 수 있고, 리액트가 개별의 아이템을 인식할 수 있게 도와주는 "key“ 속성을 사용하자.
이런식으로 목록의 아이템들이 작성되어 있었다면
<ExpenseItem
title={expense.title}
amount={expense.amount}
date={expense.date}
/>
key를 추가하여 개별의 아이템을 인식하자.
<ExpenseItem
key={expense.id}
title={expense.title}
amount={expense.amount}
date={expense.date}
/>
목록의 아이템을 매핑할 때는 항상 key를 추가하자
“2022”를 선택했더니 아무 내용도 없다.
아무 내용이 없을때 “해당목록없음” 텍스트를 추가하고싶으면 어떻게 해야할까??
{filteredExpenses.length === 0 ? (
<p>해당목록없음.</p>
) : (
filteredExpenses.map((expense) => (
<ExpenseItem
key={expense.id}
title={expense.title}
amount={expense.amount}
date={expense.date}
/>
))
)}
`` {filteredExpenses.length === 0 &&<p> 해당 목록 없음</p>}
{filteredExpenses.length >0 &&
filteredExpenses.map((expense) => (
<ExpenseItem
key={expense.id}
title={expense.title}
amount={expense.amount}
date={expense.date}
/>
))}
2번은 자바스크립트의 구문으로 ( 값1 && 값2 ) 에서 값1과 값2가 참이라면
값2를 출력하는 단축평가를 활용한것.
1번의 삼항 조건식보다 2번의 단축평가를 활용한것이 가독성이 좋아보인다.
JSX 코드에서 사용하는 방법도 있지만 따로 변수를 만들어 JSX 코드를 클린하게 만들 수도 있다.
const Expenses = (props) => {
let expensesContent = <p> 해당 목록 없음. </p>
if( filteredExpenses.length >0) {
expensesContent = filteredExpenses.map((expense) => (
<ExpenseItem
key={expense.id}
title={expense.title}
amount={expense.amount}
date={expense.date}
/>
));
}
return (
<div>
{expensesContent}
</div>
);
};
무슨 방법을 사용하든 “해당 목록 없음”이 출력된 것을 볼 수 있다.