[React] 컴포넌트 반복
컴포넌트 반복
화면에 반복적인 요소를 그릴때, 각 요소를 그려야하면 비효율적이다.
반복되는 내용을 컴포넌트로 만들어 map함수를 적용하자.
자바스크립트의 map()함수
JS 배열객체에 map함수를 적용하여 반복되는 컴포넌트를 렌더링할 수 있다.
map함수의 문법
array.map(callback, [thisArg])
callback
=> 새로운 배열의 요소를 생성하는 콜백함수
, 파라미터는
- currentValue : 현재 처리하고 있는 요소
- index : 현재 처리하고 있는 요소의 index값
- array : 현재 처리하고 있는 원본배열
this.arg
=> callback함수 내부에서 사용할 this 레퍼런스, 선택사항
map으로 데이터배열을 컴포넌트 배열로 변환
import React from "react";
const IterationSample = () => {
const names = ["눈", "크리스마스", "얼음"];
const nameList = names.map((name) => <li>{name}</li>);
return <ul>{nameList}</ul>;
};
export default IterationSample;
names의 각 요소가 nameList에 li태그로 감싸져 JSX코드로된 배열을 새로 생성한 후, nameList에 담는다.
key prop
위 코드를 그대로 렌더링하면 key prop이 없다는 경고 메세지가 표시된다.
index.js:1 Warning: Each child in a list should have a unique "key" prop.
Check the render method of `IterationSample`. See https://reactjs.org/link/warning-keys for more information.
at li
at IterationSample
at div
at App (http://localhost:3000/static/js/main.chunk.js:47:1)
위 코드를 그대로 렌더링하면 key prop이 없다는 경고 메세지가 표시된다.
key
리액트가 key를 필요로하는 이유는 컴포넌트 배열을 렌더링할때 어떤 원소가 변동이 되었는지 빠르게 찾아내기 위해 사용한다.
<ul>
<li>Duke</li>
<li>Villanova</li>
</ul>
<ul>
<li>Connecticut</li>
<li>Duke</li>
<li>Villanova</li>
</ul>
이전 Virtual DOM과 비교해, 사람이 보기에는 맨 앞에 li가 하나만 추가되었음에도
리액트는 이를 ul안의 모든 요소가 바뀐것으로 인지하고 다시 렌더링한다 -> 비효율발생
따라서 key를 부여함으로서 더 효율적인 렌더링이 가능하다
key설정
key를 설정할때는 prop설정하듯 해야한다.
이 키값은 전역공간이 아닌 형제사이
에서만 유일하면된다(li끼리만 안겹치면됨)
이 key값으로는 보통 id와같은 고유번호를 부여하는게 좋은데, 마땅한게 없다면 index값을 사용하면된다.
index를 key로사용할때 주의할점은 배열이 변경되면 효율적 리렌더링이 불가능하다
는 것이다.
응용
초기상태 -> 데이터 추가기능 -> 데이터 제거기능
초기상태설정
useState()으로 IterationSample변경
import React, { useState } from "react";
const IterationSample = () => {
const [names, setNames] = useState([
{ id: 1, text: "눈사람" },
{ id: 2, text: "얼음" },
{ id: 3, text: "눈" },
{ id: 4, text: "바람" },
]);
const [inputText, setInputText] = useState("");
const [nextId, setNextId] = useState(5);
const nameList = names.map((name) => <li key={name.id}>{name.text}</li>);
return <ul>{nameList}</ul>;
};
export default IterationSample;
데이터 추가기능
import React, { useState } from "react";
const IterationSample = () => {
const [names, setNames] = useState([
{ id: 1, text: "눈사람" },
{ id: 2, text: "얼음" },
{ id: 3, text: "눈" },
{ id: 4, text: "바람" },
]);
const [inputText, setInputText] = useState("");
const [nextId, setNextId] = useState(5);
const onChange = (e) => {
setInputText(e.target.value);
};
const onClickButton = () => {
const nextNames = names.concat({
id: nextId,
text: inputText,
});
setNextId(nextId + 1);
setNames(nextNames);
setInputText("");
};
const nameList = names.map((name) => <li key={name.id}>{name.text}</li>);
return (
<>
<input type="text" value={inputText} onChange={onChange}></input>
<button onClick={onClickButton}>확인</button>
<ul>{nameList}</ul>
</>
);
};
export default IterationSample;
Input과 확인 Button 추가됨
onChange -> Input의 text state를 유지 onClickButton -> 눌리면 현재 text state에 들어있는 내용을 nextID를 가진채로 추가.
concat함수로 불변성을 유지한다.(원본유지)
데이터 제거기능
filter함수
데이터를 추가할때 불변성을 유지하기 위해 concat함수를 이용했었다.
제거할때 불변성을 유지하기위해선 filter함수를 사용해야한다.
arr.filter(원소 => 표현식)
각 원소에 대해 표현식을 만족하는 원소로 배열을 새로 만들어 리턴한다.
filter함수 적용
numbers = [1, 2, 3, 4, 5];
const biggerthanthree = numbers.filter((number) => number > 3);
const withoutthree = numbers.filter((number) => number != 3);
const nameList = names.map((name) => (
<li key={name.id} onDoubleClick={() => onRemove(name.id)}>
{name.text}
</li>
key값으로 id가 li에 부여되고있는데, 해당 id를 가진 태그가 더블클릭되면 그 id를 인자로 받는 onRemove함수를 호출한다.
const onRemove = (id) => {
const nextNames = names.filter((name) => name.id !== id);
setNames(nextNames);
};
onRemove함수는 names state에 대해 인자로받은 id를 제외한 리스트를 새로 생성하고,
state를 업데이트한다.
댓글남기기