๐ key
๋ฆฌ์กํธ์์ key๋ ์ปดํฌ๋ํธ ๋ฐฐ์ด์ ๋ ๋๋งํ์ ๋ ์ด๋ค ์์์ ๋ณ๋์ด ์์๋์ง ์์๋ด๋ ค๊ณ ์ฌ์ฉํ๋ค.
์๋ฅผ ๋ค์ด ์ ๋์ ์ธ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃฐ ๋๋ ์์๋ฅผ ์๋ก ์์ฑํ ์๋, ์ ๊ฑฐํ ์๋, ์์ ํ ์๋ ์๋๋ฐ key๊ฐ ์์ ๋๋ Virtual DOM์ ๋น๊ตํ๋ ๊ณผ์ ์์ ๋ฆฌ์คํธ๋ฅผ ์์ฐจ์ ์ผ๋ก ๋น๊ตํ๋ฉด์ ๋ณํ๋ฅผ ๊ฐ์งํ๋ค.
ํ์ง๋ง key๊ฐ ์๋ค๋ฉด?
์ด ๊ฐ์ ์ฌ์ฉํด ์ด๋ค ๋ณํ๊ฐ ์ผ์ด๋ฌ๋์ง ๋์ฑ ๋น ๋ฅด๊ฒ ์์๋ผ ์ ์๋ค.
๐ map ํจ์์ ์ธ์๋ก ์ ๋ฌ๋๋ ํจ์ ๋ด๋ถ์์ ์ปดํฌ๋ํธ props๋ฅผ ์ค์ ํ๋ฏ ์ค์ ํ๋ฉด ๋จ.
โ key ๊ฐ์ ์ธ์ ๋ ์ ์ผํด์ผ ํจ.
๋ฐ๋ผ์ ๋ฐ์ดํฐ๊ฐ ๊ฐ์ง ๊ณ ์ณ๊ฐ์ key ๊ฐ์ผ๋ก ์ค์ ํด์ผ ํ๋ค.
// IterationSample.jsx
const IterationSample = () => {
const names = ['๋์ฌ๋', '์ผ์', '๋', '๋ฐ๋'];
const namesList = names.map((name, index) => <li key={index}>{name}</li>);
return <ul>{namesList}</ul>;
};
export default IterationSample;

์ด์ ๊ฐ๋ฐ์ ๋๊ตฌ์์ ๋ ์ด์ ๊ฒฝ๊ณ ๋ฉ์์ง๋ฅผ ํ์ํ์ง ์์ ๊ฒ!
๊ณ ์ ํ ๊ฐ์ด ์์ ๋๋ง index ๊ฐ์ key๋ก ์ฌ์ฉํด์ผ ํ๋ค. index๋ฅผ key๋ก ์ฌ์ฉํ๋ฉด ๋ฐฐ์ด์ด ๋ณ๊ฒฝ๋ ๋ ํจ์จ์ ์ผ๋ก ๋ฆฌ๋ ๋๋งํ์ง ๋ชปํ๋ค.
(+) ์์ฉํ๊ธฐ
IterationSample ์ปดํฌ๋ํธ์์ useState๋ฅผ ์ฌ์ฉํด ์ํ๋ฅผ ์ค์ .
์ด๋ฒ์๋ ๊ฐ์ฒด ํํ๋ก ์ด๋ฃจ์ด์ง ๋ฐฐ์ด์ ๋ง๋ค์ด๋ณด์! ๊ทธ๋ฆฌ๊ณ ํด๋น ๊ฐ์ฒด์๋ ๋ฌธ์์ด๊ณผ ๊ณ ์ id ๊ฐ์ด ์์.
// IterationSample.jsx
// 6.4.1 ์์ฉํ๊ธฐ
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); // ์๋ก์ด ํญ๋ชฉ์ ์ถ๊ฐํ ๋ ์ฌ์ฉํ id
const namesList = names.map((name) => <li key={name.id}>{name.text}</li>);
return <ul>{namesList}</ul>;
};
export default IterationSample;

(+) ์กฐ๊ธ ๋ ์์ฉํด์ '์ถ๊ฐ' ๋ฒํผ ๋ง๋ค์ด๋ณด๊ธฐ
// 6.4.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);
const onChange = (e) => setInputText(e.trarget.value);
const nameList = names.map((name) => <li key={name.id}>{name.text}</li>);
return (
<>
<input type={inputText} onChange={onChange} />
<button>์ถ๊ฐ</button>
<ul>{nameList}</ul>
</>
);
};
export default IterationSample;


๊ทธ๋ค์์๋ ๋ฒํผ์ ํด๋ฆญํ์ ๋ ํธ์ถํ onClick ํจ์๋ฅผ ์ ์ธํด์ ๋ฒํผ์ onClick ์ด๋ฒคํธ๋ก ์ค์ ํด๋ณด์.
onClick ํจ์์์๋ ๋ฐฐ์ด์ ๋ด์ฅ ํจ์ concat์ ์ฌ์ฉํด ์๋ก์ด ํญ๋ชฉ์ ์ถ๊ฐํ ๋ฐฐ์ด์ ๋ง๋ค๊ณ , setNames๋ฅผ ํตํด ์ํ๋ฅผ ์
๋ฐ์ดํธํด ์ค๋ค.
// 6.4.2 ๋ฐ์ดํฐ ์ถ๊ฐ ๊ธฐ๋ฅ ๊ตฌํํ๊ธฐ
// 6.4.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); // ์๋ก์ด ํญ๋ชฉ์ ์ถ๊ฐํ ๋ ์ฌ์ฉํ 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 namesList = names.map((name) => <li key={name.id}>{name.text}</li>);
return (
<>
<input value={inputText} onChange={onChange} />
<button onClick={onClick}>์ถ๊ฐ</button>
<ul>{namesList}</ul>
</>
);
};
export default IterationSample;


๋ฆฌ์กํธ์์ ์ํ๋ฅผ ์ ๋ฐ์ดํธํ ๋๋ ๊ธฐ์กด ์ํ๋ฅผ ๊ทธ๋๋ก ๋๋ฉด์ ์๋ก์ด ๊ฐ์ ์ํ๋ก ์ค์ ํด์ผ ํ๋ค. ์ด๋ฅผ ๋ถ๋ณ์ฑ ์ ์ง๋ผ๊ณ ํ๋๋ฐ, ๊ทธ๋์ผ ๋์ค์ ๋ฆฌ์กํธ ์ปดํฌ๋ํธ์ ์ฑ๋ฅ์ ์ต์ ํํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
(+) ๋๋ธ ํด๋ฆญํ๋ฉด ์ญ์ ๋๋ ๊ฒ๋ ์ถ๊ฐํด๋ณด์...
// ๊ธฐ์กด ์ถ๊ฐ ๊ธฐ๋ฅ ๊ตฌํ ์ฃผ์ ์ฒ๋ฆฌํ๊ณ ...
// const namesList = names.map((name) => <li key={name.id}>{name.text}</li>);
//
// ์ถ๊ฐ + ์ญ์ ๊ธฐ๋ฅ ๊ตฌํ
const onRemove = id => {
const nextNames = names.filter(name => name.id !== id);
setNames(nextNames);
};
const namesList = names.map(name => (
<li key={name.id} onDoubleClick={() => onRemove(name.id)}>
{name.text}
</li>
));

