6.1 자바스크립트 배열의 map() 함수
자바스크립트 배열 객체의 내장 함수인 map 함수를 사용하여 반복되는 컴포넌트를 렌더링할 수 있다.
map 함수는 파라미터로 전달된 함수를 사용해서 배열 내 각 요소를 원하는 규칙에 따라 변환한 후 그 결과로 새로운 배열을 생성한다.
arr.map(callback, [thisArg])
callback: 새로운 배열의 요소를 생성하는 함수로 파라미터는 다음 3가지다.
- currentValue: 현재 처리하고 있는 요소
- index: 현재 처리하고 있는 요소의 index 값
- array: 현재 처리하고 있는 원본 배열
thisArg(선택 항목): callback 함수 내부에서 사용할 this 레퍼런스
map 함수를 사용하여 배열 [1,2,3,4,5]의 각 요소를 제곱해서 새로운 배열을 생성하자.
var numbers = [1,2,3,4,5];
var processed = numbers.map(function(num) {
return num*num;
});
console.log(processed);
console 출력: [1, 4, 9, 16, 25]
↓
[ ES6 문법 ]
const numbers = [1,2,3,4,5];
const result = numbers.map(num=> num*num);
console.log(result);
→ map 함수는 기존 배열로 새로운 배열을 만드는 역할을 함
6.2 데이터 배열을 컴포넌트 배열로 변환
1) 컴포넌트 수정하기
IterationSample.js
import React from 'react'
const IterationSample = () => {
const names = ['눈사람','얼음','눈','바람'];
const nameList = names.map(name => <li>{name}</li>);
return <ul>{nameList}</ul>
};
export default IterationSample;
map 함수에서 JSX를 작성할 때는 앞의 예제처럼 DOM 요소를 작성해도 되고, 컴포넌트를 사용해도 된다.
2) App 컴포넌트에서 예제 컴포넌트 렌더링
import React, {Component} from 'react';
import IterationSample from './IteratonSample';
class App extends Component{
render(){
return (
<IterationSample/>
);
}
}
export default App;
→ "key" prop이 없다는 경고 메세지 출력
6.3 key
- 리액트에서 key는 컴포넌트 배열을 렌더링했을 때 어떤 원소에 변동이 있었는지 알아내려고 사용한다.
- 예를 들어 유동적인 데이터를 다룰 때는 원소를 새로 생성할 수도, 제거할 수도, 수정할 수도 있다.
- key가 없을 때는 Virtual DOM을 비교하는 과정에서 리스트를 순차적으로 비교하면서 변화를 감지한다.
- key가 있다면 이 값을 사용하여 어떤 변화가 일어났는지 더욱 빠르게 알아낼 수 있다.
1) key 설정
key값은 언제나 유일해야 한다. key값을 설정할 때는 map함수의 인자로 전달되는 함수 내부에서 컴포넌트 props를 설정하듯이 설정을 하면 된다.
IterationSample.js
import React from 'react';
const IterationSample = () =>{
const names = ['눈사람','얼음','눈','바람'];
const nameList = names.map((name,index) => <li key={index}>{name}</li>;
return <ul>{namelist}<ul>
};
export default IterationSample;
→ 고유한 값이 없을 때만 index값을 key로 사용해야 한다. index를 key로 사용하면 배열이 변경될 때 효율적으로 리렌더링하지 못하기 때문이다.
6.4 응용
1) 초기 상태 설정하기
IterationSample 컴포넌트에서 useState를 사용하여 상태를 설정해보자.
- 데이터 배열
- 텍스트를 입력할 수 있는 input의 상태
- 데이터 배열에서 새로운 항목을 추가할 때 사용할 고유 id를 위한 상태
IterationSample.js
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); // 새로운 항목이 추가 될때, 5번 index 부터 시작됨.
const nameList = names.map(name => <li key={name.id}/>{name.text}</li>);
return <ul>{nameList}</ul>;
export default IterationSample;
2) 데이터 추가 기능 구현하기
새로운 이름을 등록할 수 있는 기능을 구현해보자.
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); // 새로운 항목이 추가 될때, 5번 index 부터 시작됨.
const onChange = e => setInputText(e.target.value);
const onClick =()=>{
const nextNames = names.concat({
id:nextId,
text: inputText
});
setNextId(nextId+1); // nextId +1
setNames(nextNames); // names 배열의 값 업데이트
setInputText(''); // inputText를 비운다.
};
const nameList = names.map(=><li key={name.id}/>{name.text}</li>);
return (
<>
<input value={inputText} onChange={onChange}/>
<button onClick={onClick}>추가</button>
<ul>{nameList}</ul>
</>
);
}
export default IterationSample;
- ul 태그 상단에 input과 button을 렌더링하고, input 상태 관리하기
- 버튼을 클릭했을 때 호출할 onClick 함수에서는 배열 내장 함수 concat을 사용하여 새로운 항목을 추가한 배열을 만들고, setNames를 통해 상태를 업데이트 한다.
- push 함수는 기존 배열 자체를 변경해 주는 반면, concat은 새로운 배열을 만들어 준다는 차이점이 있다.
3) 데이터 제거 기능 구현하기
각 항목을 더블클릭했을 때 해당 항목이 사라지는 기능을 구현해보자.
마찬가지로 불변성을 유지하면서 업데이트해 주어야 한다. 불변성을 유지하면서 배열의 특정 항목을 지울 때는 배열 내장 함수 filter를 사용한다.
filter 함수를 사용하면 배열에서 특정 조건을 만족하는 원소들만 쉽게 분류할 수 있다.
const numbers = [1,2,3,4,5,6];
const biggerThanThree = numbers.filter(number => number > 3);
// 결과: [4,5,6]
IterationSample.js
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); // 새로운 항목이 추가 될때, 5번 index 부터 시작됨.
const onChange = e => setInputText(e.target.value);
const onClick =()=>{
const nextNames = names.concat({
id:nextId,
text: inputText
});
setNextId(nextId+1); // nextId +1
setNames(nextNames); // names 배열의 값 업데이트
setInputText(''); // inputText를 비운다.
};
const onRemove = id =>{
const nextNames = nemes.filter(name=>name.id!==id);
setNames(nextNames);
};
const nameList = names.map(=>(
<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;
6.5 정리
- 반복되는 데이터를 렌더링하는 방법을 배우고, 이를 응용하여 유동적인 배열을 다루었다.
- key 값은 늘 유일해야 하고, key 값이 중복된다면 렌더링 과정에서 오류가 발생한다.
- 상태 안에서 배열을 변형할 때는 배열에 직접 접근하여 수정하는 것이 아니라 concat, filter 등의 배열 내장 함수를 사용하여 새로운 배열을 만든 후 이를 새로운 상태로 설정해야 한다.
'React > [책] 리액트를 다루는 기술' 카테고리의 다른 글
8장. Hooks (0) | 2021.07.28 |
---|---|
7장. 컴포넌트의 라이프사이클 메서드 (0) | 2021.07.21 |
5장. ref.DOM에 이름 달기 (0) | 2021.07.20 |
3장. 컴포넌트(2) (0) | 2021.07.16 |
4장. 이벤트 핸들링 (0) | 2021.07.14 |