
오늘의 나는 무엇을 배웠을까?
배열 렌더링을 하기 위해서 다음과 같이
//Child
import React from "react";
export default function Child({ name }) {
return <li>name : {name}</li>;
}
Child 컴포넌트를 만들고
//ShowName
import React from "react";
import Child from "./Child";
export Default ShowName() {
const names = ['a', 'b', 'c', 'd', 'e'];
return (
<div>
<h1>이름 목록</h1>
<ul>
<Child name={ names[0] }/>
<Child name={ names[1] }/>
...
</ul>
</div>
)
}
ShowName 컴포넌트를 만든 뒤
//App
import ShowName from "./ShowName";
export default App() {
return (
<div>
<ShowName />
</div>
)
}
ShowName 컴포넌트를 불러와 렌더링할 수도 있다. 하지만, 값을 내려주기 위해 일일이 작성하는 것은 매우 비효율적이다.
이때 사용할 수 있는 것이 배열의 map 메소드이다.
map 메소드는 배열의 메소드로써, 배열에 함수를 호출하여 새로운 배열을 만들게 된다.
배열의 각 요소에 한번씩 함수를 호출하고, 빈 요소에 대해서는 호출하지 않는다. 또, 기존 배열은 수정되지 않은채 새로운 배열을 만들게 된다.
map 메소드를 활용하면 다음과 같이 코드를 수정할 수 있다.
//ShowName
//...
export default ShowName() {
const names = ['a', 'b', 'c', 'd', 'e'];
return (
<div>
<h1>이름 목록</h1>
<ul>
{ names.map((name) => <Child name={name} />) }
</ul>
</div>
)
}
배열 요소마다 한번씩 함수를 호출하여 해당 요소를 prop으로 가진 Child 컴포넌트를 생성한다. 매우 간단해 졌다.
고로, 배열을 렌더링 할 떄는 map 메소드를 적극 활용하자.
배열의 sort 메소드를 통해 정렬해 줄 수 있다.
array.sort([compare function])비교함수의 형식은
function compare(a,b) {
if (a is less than b by some ordering criterion) {
return -1;
}
if (a is greater than b by the ordering criterion) {
return 1;
}
// a must be equal to b
return 0;
}
과 같고, 두개의 매개변수를 받고 내부 로직을 실행하여 비교한다.
//ReviewList.js
function ReviewListItem({ item, onDelete }) {
const handleDeleteClick = () => onDelete(item.id);
return (
<div className="ReviewListItem">
<img className="ReviewListItem-img" src={item.imgUrl} alt={item.title} />
<div>
<h1>{item.title}</h1>
<p>{item.rating}</p>
<p>{formatDate(item.createdAt)}</p>
<p>{item.content}</p>
<button onClick={handleDeleteClick}>삭제</button>
</div>
</div>
);
}
function ReviewList({ items, onDelete }) {
return (
<ul>
{items.map((item) => {
return (
<li key={item.id}>
<ReviewListItem item={item} onDelete={onDelete} />
</li>
);
})}
</ul>
);
}
//App.js
function App() {
//~~~
const handleDelete = (id) => {
console.log(items);
const nextItems = items.filter((item) => item.id !== id);
setItems(nextItems);
};
//~~~
return (
<div>
<div>
<button onClick={handleNewestClick}>최신순</button>
<button onClick={handleBestClick}>베스트순</button>
</div>
<ReviewList items={sortedItems} onDelete={handleDelete} />
{hasNext && <button onClick={handleLoadMore}>더 보기</button>}
</div>
);
}
위와 같은 코드가 있다면, handleDelete 함수는 filter 메소드를 이용하여 item.id 값이 일치하지 않는 배열의 요소만 추출하여 새로운 배열을 만들게 된다. 즉, item.id를 id 값으로 갖는 원소만 제거하는 것과 동일해 진다.
ReviewListItem 컴포넌트의 삭제 버튼이 클릭될 때 props로 받아올 onDelete 함수의 매개변수로 item.id 가 전달되어야 한다. onDelete 함수는 ReviewList 에서도 전달 받으며 그대로 ReviewListItem 컴포넌트에 전달된다.
배열을 렌더링 할 때, 의도하지 않는 방식의 결과가 나타나거나 비효율적인 동작을 막기 위해 key를 사용해야 한다.
가령, 아래와 같은 배열을
const array = ["a", "b", "c", "d"];
다음과 같이 렌더링 한다고 할 때
array.map(item => <div>{item}</div>);
b 와 c 사이에 새로운 요소 z를 삽입하게 되면,
<div>b</div> 와 <div>c</div> 사이에 새로운 태그를 삽입하는 것이 아닌, c → z / d → c / 마지막에 d 가 새로 삽입되는 과정으로 re-rendering이 일어나게 된다.
또한, a가 제거 되면 a→b / b→c / c→d / 마지막의 d가 제거되는 과정으로 re-rendenring이 일어나는 매우 비효율적인 동작을 하게 된다.
Key를 활용하면 이러한 불필요한 작업을 개선시킬 수 있는데,
[
{
id: 0,
text: 'a'
},
{
id: 1,
text: 'b'
},
{
id: 2,
text: 'c'
},
{
id: 3,
text: 'd'
}
];
위의 id와 같이 key로 사용할 수 있는 고유값이 객체에 있고,
array.map(item => <div key={item.id}>{item.text}</div>
와 같이 렌더링을 한다면 배열이 업데이트 되어도 수정되지 않는 기존 값은 그대로 두고 원하는 곳에 내용을 삽입하거나 삭제할 수 있게 된다. 훨씬 더 효율적인 렌더링을 할 수 있게 되는 것이다.
오늘의 나는 어떤 어려움이 있었을까?
사실 아직 props state에 대해 잘 모르겠다. React를 사용하며 가장 중요한 두 요소인 것 같은데, 내일 보충학습을 통해 제대로 알아보고 학습을 진행해야 겠다.
뭔가 느낌상 하나를 제대로 모른채로 넘어가니 뒷내용도 어영부영 되는 느낌이 있는 것 같은데, 시간을 조금 더 들여 이해하려고 노력해야겠다.
내일의 나는 무엇을 해야할까?