반응형
자바 스크립트 배열의 map() 함수
자바 스크립트 배열 객체의 내장 함수인 map 함수를 사용하여 반복되는 컴포넌트를 렌더링할 수 있다. map 함수는 파라미터로 전달된 함수를 사용해서 배열 내 각 요소를 원하는 규칙에 따라 변환한 후 그 결과로 새로운 배열을 생성한다.
문법
arr.map(callback, [thisArg])
- callback : 새로운 배열의 요소를 생성하는 함수
- currentValue : 현재 처리하고 있는 요소
- index : 현재 처리하고 있는 요소의 index값
- array : 현재 처리하고 있는 원본 배열
- thisArg(선택항목) : callback 함수 내부에서 사용할 this 레퍼런스
예제
//IterationSample.js
const IterationSample = () => {
const names = ['눈사람', '얼음', '눈', '바람'];
const nameList = names.map(name => <li>{ name }</li>);
return <ul>{ nameList }</ul>
};
export default IterationSample;
//App.js
import IterationSample from './IterationSample';
function App() {
return <IterationSample />;
};
export default App;
실행 화면을 보면 원하는 대로 렌더링이 되었다. 하지만, console 창에서 "key"prop이 없다는 경고 메세지를 표시한 것을 볼 수 있다. 여기서의 key란 무엇일까?
Key
- key 값 : map() 함수를 호출할 때 인자로 넘기는 Callback 함수의 인자로 넘어오는 index 값
- 컴포넌트를 렌더링 하였을 때 어떤 원소가 변경되었는지 빠르게 감지하기 위해 사용
- 만약 key가 설정되지 않았다면?
가상 DOM을 순차적으로 비교하면서 감지하기 때문에 key가 없을때보다 속도가 느리다.
key 설정
- map 함수의 인자로 전달되는 함수 내부에서 컴포넌트 props를 설정하듯이 설정
- key 값은 언제나 유일해야 함 -> 데이터가 가진 고유 값을 key값으로 설정해야 한다.
- 만약 고유한 값이 없으면? => index 값을 key로 사용
- index를 key로 사용하면 배열이 변경될 때 효율적으로 리렌더링하지 못함.
//IterationSample.js
const IterationSample = () => {
const names = ['눈사람', '얼음', '눈', '바람'];
const nameList = names.map((name, index) => <li key = {index} >{ name } </li>);
return <ul>{ nameList }</ul>
};
export default IterationSample;
응용 - 동적인 배열을 렌더링하기
1. 초기 상태 설정하기
//IterationSample.js
import { 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); // 새로운 항목을 추가할 때 사용할 id
const nameList = names.map(name => <li key = {name.id} >{ name.text } </li>);
return <ul>{ nameList }</ul>
};
export default IterationSample;
2. 데이터 추가 기능 구현하기
새로운 이름을 등록할 수 있는 기능 구현
//IterationSample.js
import { 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); // 새로운 항목을 추가할 때 사용할 id
const onChange = e => setInputText(e.target.value);
const nameList = names.map(name => <li key = {name.id} >{ name.text } </li>);
return (
<>
<input value = { inputText } onChange = { onChange } />
<button>추가</button>
<ul>{ nameList }</ul>
</>
);
};
export default IterationSample;
2-1. onClick 이벤트 설정
- 배열의 내장함수
concat
을 사용하여 새로운 항목을 추가한 배열을 만들고,setNames
를 통해 상태 업데이트 - 새로운 항목을 추가할 때, 객체의 id값 :
nextId
값을 사용 - 클릭될 때 마다 값이 1씩 올라가도록 구현
//IterationSample.js
import { 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); // 새로운 항목을 추가할 때 사용할 id
const onChange = e => setInputText(e.target.value);
const onClick = () => {
const nextNames = names.concat({
id : nextId, //nextId 값을 id로 설정하고
text : inputText
});
setNextId(nextId + 1);
setNames(nextNames);
setInputText(''); // inputText를 비운다.
}
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;
push
vs concat
push
: 기존 배열 자체를 변경
concat
: 새로운 배열을 만들어줌
3. 데이터 제거 기능 구현하기
- 각 항목을 더블클릭했을 때 해당 항목이 화면에서 사라지는 기능 구현
- 불변성을 유지하면서 업데이트 -> 배열의 내장함수
filter
사용
- 불변성을 유지하면서 업데이트 -> 배열의 내장함수
//IterationSample.js
import { 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); // 새로운 항목을 추가할 때 사용할 id
const onChange = e => setInputText(e.target.value);
const onClick = () => {
const nextNames = names.concat({
id : nextId, //nextId 값을 id로 설정하고
text : inputText
});
setNextId(nextId + 1);
setNames(nextNames);
setInputText(''); // inputText를 비운다.
}
const onRemove = id => {
const nextNames = names.filter(name => name.id !== id);
setNames(nextNames);
}
const nameList = names.map(name => (
<li key = {name.id} onDoubleClick={() => onRemove(name.id)}>
{ name.text }
</li>
));
return (
<>
<input value = { inputText } onChange = { onChange } />
<button onClick={ onClick }>추가</button>
<ul>{ nameList }</ul>
</>
);
};
export default IterationSample;
정리
- 컴포넌트 배열을 렌더링할 때, key 값 설정에 항상 주의해야한다.(유일성)
- 상태 안에서 배열을 변형할 때, 배열에 직접 접근하여 수정하는 것이 아니라, concat, filter 등의 배열 내장 함수를 사용하여 새로운 배열을 만든 후 이를 새로운 상태로 설정해주어야한다.
이 글은 김민준 님의 리액트를 다루는 기술을 읽고 정리한 내용입니다.
반응형