리액트에서 코드가 반복될 때 효율적으로 관리하는 법
let arr = [1,2,3,4,5];
let newArr = arr.map(function(num) {
return num*num;
}
// ES6 문법
let newArr2 = arr.map(num => num*num);
console.log(newArr); // [1,4,9,16,25]
같은 원리로 기본 배열로 컴포넌트로 구성된 배열을 생성할 수 있다
이 코드를
const IterationSample = () => {
return (
<ul>
<li>a</li>
<li>b</li>
<li>c</li>
<li>d</li>
</ul>
);
};
다음과 같이 바꿀 수 있다
const IterationSample = () => {
const names = ['a', 'b', 'c', 'd']; // 문자열로 구성된 배열 선언
// <li>...</li> 로 된 배열 새로 생성하고 nameList에 담는다
const nameList = names.map(name => <li>{name}</li>);
return <ul>{nameList}</ul>
}
map함수에서 JSX작성할 때 DOM요소로 작성해도 되고 컴포넌트 사용해도 됨
실행은 되지만 개발자 도구에서 "key" prop이 없다는 경고 메시지 표시
key
리액트에서 key은 컴포넌트 배열 렌더링 했을 때 어떤 원소의 변동 있었는지 알아내려고 사용
key 없을 때는 리스트 순차적으로 비교
어떤 변화 일어났는지 빠르게 알아냄 (원소 생성, 제거, 수정 등)
key 설정
map함수의 인자로 전달되는 콜백 함수 내부에서 컴포넌트 props 설정하듯 하면 됨
key 값은 유일해야 함. 데이터의 고유 값 또는 index(index는 고유한 값 없을때만. 인덱스를 키로 사용하면 배열 변경될 때 리렌더링 효율적이지 못함)
const IterationSample = () => {
const names = ['a', 'b', 'c', 'd'];
// 인덱스를 key로. 경고 메세지 안뜸
const nameList = names.map((name, index) => <li key = {index}>{name}</li>);
return <ul>{nameList}</ul>
}
이전엔 단순히 문자열로 이뤄진 배열을 만들었지만 이번엔 객체 형태로 이뤄진 배열을 만든다
해당 객체에는 문자열과 고유 id값이 있다
const IterationSample = () => {
const [names, setNames] = useState([
{id:1, text: 'aa'},
{id:2, text: 'bb'},
{id:3, text: 'cc'},
{id:4, text: 'dd'},
]);
const [inputText, setInputText] = useState('');
const [nextId, setNextId] = useState(5); // 새로운 항목 추가할때 사용할 id
// map함수 사용 시 key값을 index 대신 name.id로 지정
const nameList = names.map(name=> <li key = {name.id}>{name.text}</li>);
return <ul>{nameList}</ul>
}
import React, {useState} from 'react';
const IterationSample = () => {
const [names, setNames] = useState([
{id:1, text: 'aa'},
{id:2, text: 'bb'},
{id:3, text: 'cc'},
{id:4, text: 'dd'},
]);
const [inputText, setInputText] = useState('');
const [nextId, setNextId] = useState(5); // 새로운 항목 추가할때 사용할 id
const onChange = e => setInputText(e.target.value); // inputText값을 input에 입력한 값으로 변경
const onClick = () => {
const nextNames = names.concat({ // names에 새로운 원소 추가 후 반환
// push 대신 concat사용한 이유는 불변성 유지해 성능 최적화 위해
id: nextId, // id값은 nextId로
text: inputText
});
setNextId(nextId + 1);
setNames(nextNames); // names값 업데이트
setInputText (''); // inputText를 비움
}
// map함수 사용 시 key값을 index 대신 name.id로 지정
const nameList = names.map(name=> <li key = {name.id}>{name.text}</li>);
return (
<>
<input value = {inputText} onChange = {onChange} />
<button onClick = {onClick}>추가</button>
<ul>{nameList}</ul>
</>
)
}
export default IterationSample;
...
const onRemove = id => {
// filter 이용해 더블클릭한 id 삭제
const nextNames = names.filter(name => name.id !== id);
setNames(nextNames);
};
// map함수 사용 시 key값을 index 대신 name.id로 지정
const nameList = names.map(name => <li key = {name.id}
// 더블클릭 시 onRemove()
onDoubleClick = {() => onRemove(name.id)}>{name.text}</li>);
return (
<>
<input value = {inputText} onChange = {onChange} />
<button onClick = {onClick}>추가</button>
<ul>{nameList}</ul>
</>
)