6.3 key
- 리액트에서 key는 컴포넌트 배열을 렌더링했을 때 어떤 원소에 변동이 있었는지 알아내려고 사용한다.
- key가 없을 때는 Virtual DOM을 비교하는 과정에서 리스트를 순차적으로 비교하면서 변화를 감지하지만 key가 있다면 이 값을 사용하여 어떤 변화가 일어났는지 더욱 빠르게 알아낼 수 있다.
6.3.1 key 설정
- key 값을 설정할 때는 map 함수의 인자로 전달되는 함수 내부에서 컴포넌트 props를 설정하듯이 설정하면 된다.
- key 값은 언제나 유일해야 한다.
![](https://velog.velcdn.com/images/jeong_yooony/post/8d75b112-d3e8-413a-a2e9-59264f630930/image.png)
- key 설정 전에는 위 사진과 같이 "key" prop이 없다는 경고 메시지를 표시한다.
▶ IterationSample.js
const IterationsSample = () => {
const names = ['눈사람', '얼음', '눈', '바람'];
const nameList = names.map((name, index) => <li key={index}>{name}</li>);
return <ul>{nameList}</ul>;
}
export default IterationsSample;
- map함수에 전달되는 콜백 함수의 인수인 index값을 사용하여 고유 번호를 지정해준다.
- 코드를 위와 같이 수정하면 더 이상 경고메시지가 뜨지 않는다.
- index를 key로 사용하면 배열이 변경될 때 효율적으로 리렌더링하지 못하므로 고유값이 없을 때만 index 값을 key로 사용하도록 한다.
6.4 응용
- 고윳값을 만들어 동적인 배열을 렌더링하는 것을 구현해보자.
6.4.1 초기 상태 설정하기
- IterationSample 컴포넌트에서 useState를 사용하여 상태를 설정해보자.
- 세 가지 상태 중에서 하나는 데이터 배열이고, 다른 하나는 텍스트를 입력할 수 있는 input의 상태, 마지막 하나는 데이터 배열에서 새로운 항목을 추가할 때 사용할 고유 id를 위한 상태이다.
- 객체 형태로 이루어진 배열을 만들어보자.
▶ IterationSample.js
import {useState} from 'react';
const IterationsSample = () => {
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 IterationsSample;
- map 함수를 사용할 때 key 값을 index 대신 name.id값으로 지정해 주었다.
6.4.2 데이터 추가 기능 구현하기
- 새로운 이름을 등록할 수 있는 기능 구현
- ul 태그 상단에 input과 button을 렌더링하고, input의 상태를 관리
- 버튼을 클릭했을 때 호출할 onClick 함수를 선언하여 버튼의 onClick 이벤트로 설정
- onClick 함수에서의 배열의 내장 함수 concat을 사용하여 새로운 항목을 추가한 배열을 만들고, setNames를 통해 상태 업데이트를 해준다.
▶ IterationSample.js
import {useState} from 'react';
const IterationsSample = () => {
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); // nextId 값에 1을 더해 준다.
setNames(nextNames); // names 값을 업데이트한다.
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 IterationsSample;
- push 함수는 기존 배열 자체를 변경해주지만, concat은 새로운 배열을 만들어 준다는 차이점이 있다.
- 리액트에서 상태를 업데이트할 때는 기존 상태를 그대로 두면서 새로운 값을 상태로 설정해야 한다.
- onClick 함수에서 새로운 항목을 추가할 때 객체의 id 값은 nextId를 사용하도록 하고, 클릭될 때마다 값이 1씩 올라가도록 구현한다.
- button이 클릭될 때 기존의 input 내용을 비우는것도 구현해 준다.
![](https://velog.velcdn.com/images/jeong_yooony/post/5d06c561-3d04-4d2d-851f-df320a7d506f/image.png)
![](https://velog.velcdn.com/images/jeong_yooony/post/162e4ffa-175a-4513-ab5b-09776c4f6ba9/image.png)
- input에 입력값을 입력하고 버튼을 누르면 새 항목이 추가된다.
6.4.3 데이터 제거 기능 구현하기
- 각 항목을 더블클릭햇을 때 해당 항목이 사라지는 기능을 구현해 보는데 불변성을 유지하면서 배열의 특정 항목을 지울 때는 배열의 내장 함수 filter를 사용한다.
import {useState} from 'react';
const IterationsSample = () => {
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); // nextId 값에 1을 더해 준다.
setNames(nextNames); // names 값을 업데이트한다.
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 IterationsSample;
![](https://velog.velcdn.com/images/jeong_yooony/post/7636aa47-59c3-4ee2-9995-5574b8f7e804/image.png)
![](https://velog.velcdn.com/images/jeong_yooony/post/1f85ffdd-f21e-4808-b204-195b0f59d62f/image.png)
- HTML요소를 더블클릭할 때 사용하는 이벤트의 이름은 onDoubleClick이다.
- onRemove라는 함수를 구현해서 각 li 요소에 이벤트로 등록해 준다.
- onRemove 함수에서는 클릭할 때 클릭이 발생한 li 요소의 id를 매개변수로 받아 해당 id를 가진 name 객체를 제거하고, 필터링 된 배열 nextNames로 names를 업데이트 한다.
정리
- 배열을 변형할 때는 배열에 직접 접근하여 수정하는 것이 아니라 concat, filter등의 배열 내장 함수를 사용하여 새로운 배열을 만든 후 이를 새로운 상태로 설정해 주어야 한다는 점을 기억하자.
7. 컴포넌트의 라이프 사이클 메서드
- 모든 리액트 컴포넌트에는 라이프 사이클(수명주기)이 존재한다.
- 리액트 프로젝트를 진행하다 보면, 컴포넌트를 처음으로 렌더링 할 때 혹은 컴포넌트를 업데이트하기 전후로 어떤 작업을 처리해야 할 수도 있고, 불필요한 업데이트를 방지해야 할 때가 있는데 이때 컴포넌트의 라이프 사이클 메서드를 사용한다.
7.1 라이프사이클 메서드의 이해
![](https://velog.velcdn.com/images/jeong_yooony/post/b4316f84-dd02-40d4-a658-10146093394e/image.png)
![](https://velog.velcdn.com/images/jeong_yooony/post/c7a86ccb-644b-4d4d-a7e7-1d528ebef1fc/image.png)
- 위 사진들은 컴포넌트의 라이프사이클이다.
- 라이프사이클 메서드는 총 9가지이다.
- Will 접두사 - 어떤 작업을 작동하기 전에 실행되는 메서드
- Did 접두사 - 어떤 작업을 작동한 후에 실행되는 메서드
- 위 메서드들은 컴포넌트 클래스에서 덮어서 선언함으로 사용할 수 있다.
마운트
- DOM이 생성되고 웹 브라우저상에 컴포넌트가 나타나는 것을 마운트라고 한다.
![](https://velog.velcdn.com/images/jeong_yooony/post/016f7f6a-2a6b-4360-8d32-93c3e3cc1b42/image.png)
- 위 사진은 마운트 할 때 호출하는 메서드이다.
- constructor : 컴포넌트를 새로 만들 때마다 호출되는 클래스 생성자 메서드입니다.
- getDerivedStateFromProps 메서드 : props에 있는 값을 state에 넣을 때 사용하는 메서드
- render 메서드 : 준비한 UI를 렌더링 하는 메서드
4 .componentDidMount 메서드 : 컴포넌트가 웹 브라우저상에 나타난 후에 호출하는 메서드
업데이트
- 컴포넌트 정보를 업데이트(리렌더링) 한다.
- 컴포넌트는 다음과 같은 총 네 가지 경우에 업데이트를 한다.
- props가 바뀔 때
- state가 바뀔 때
- 부모 컴포넌트가 리렌더링될 때
- this.forceUpdate로 강제로 렌더링을 트리거 할 때
![](https://velog.velcdn.com/images/jeong_yooony/post/324eb0b8-9e3a-4b13-8997-680b6f1284b4/image.png)
- 위 사진은 업데이트 할 때 호출하는 메서드이다.
- getDerivedStateFromProps 메서드 : props에 있는 값을 state에 넣을 때 사용하는 메서드(마운트에서도 호출됨)
- shiuldComponenetUpdate 메서드 : 컴포넌트가 리렌더링을 해야 할지 말아야 할지를 결정하는 메서드(true를 반환하면 리렌더링, false 면 리렌더링 하지 않음)
- render 메서드 : 준비한 UI를 렌더링 하는 메서드
- getSnapshotBeforeUpdate : 컴포넌트 변화를 DOM에 반영하기 직전에 호출하는 메서드
- componentDidUpdate : 컴포넌트의 업데이트 작업이 끝난 후 호출하는 이벤트
언마운트
![](https://velog.velcdn.com/images/jeong_yooony/post/047f5f0a-6743-414a-9b8e-f7b6603c70a0/image.png)
- 위 사진은 언마운트 할 때 호출하는 메서드이다.
- componentWillUnmount : 컴포넌트가 웹 브라우저상에서 사라지기 전에 호출하는 메서드입니다.