const todos = [
{
id: 2,
value: "cook",
},
{
id: 1,
value: "homework",
},
{
id: 3,
value: "study",
},
{
id: 4,
value: "work out",
},
];
const TodoApp = () => {
const [items, setItems] = useState(todos);
const handleDoneClick = (data) => {
setItems((prev) => prev.filter((item) => item.id !== data.id));
};
return (
<ul>
{items.map((data) => (
<li>
<button onClick={() => handleDoneClick(data)}>{data.value}</button>
</li>
))}
</ul>
);
};
๋ค์๊ณผ ๊ฐ์ ์ปดํฌ๋ํธ๊ฐ ์๋ค. ๋ ๋๋ง์ ์ ์์ ์ผ๋ก ์ด๋ฃจ์ด์ง์ง๋ง ์ฝ์์ ์ค๋ฅ๋ฅผ ๋ฑ์ด๋ธ๋ค.
list์ ๊ฐ child๋ ๊ณ ์ ํ key prop์ด ์์ด์ผํ๋ค. ์ด๊ฒ ๋ฌด์จ ์๋ฆฌ์ผ๊น? ์ผ๋จ ๊ณต์ ๋ฌธ์๋ถํฐ ์ฐพ์๋ณด์.
Key๋ React๊ฐ ์ด๋ค ํญ๋ชฉ์ ๋ณ๊ฒฝ, ์ถ๊ฐ ๋๋ ์ญ์ ํ ์ง ์๋ณํ๋ ๊ฒ์ ๋์ต๋๋ค. key๋ ์๋ฆฌ๋จผํธ์ ์์ ์ ์ธ ๊ณ ์ ์ฑ์ ๋ถ์ฌํ๊ธฐ ์ํด ๋ฐฐ์ด ๋ด๋ถ์ ์๋ฆฌ๋จผํธ์ ์ง์ ํด์ผ ํฉ๋๋ค.
Key๋ ๊ณ ์ ์ฑ์ ๋ถ์ฌํ๋ ์์ฑ์ด๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ์๋ฆฌ๋จผํธ๋ฅผ ์๋ณํ๋ ๊ฐ์ผ๋ก ์ง์ ํ๋ ๊ฒ ์ข๋ค.
{items.map((data) => (
<li key={data.id}>
<button onClick={() => handleDoneClick(data)}>{data.value}</button>
</li>
))}
์์ ์์์์๋ id ๊ฐ์ด data๋ง๋ค ์กด์ฌํ๋ id๋ก ๋ถ์ฌํ๋ ๊ฒ ์ข๊ฒ ๋ค.
key๋ ํ์ฌ ๋ฐฐ์ด context์์ ๋ถ์ฌ๋์ด์ผ ํ๊ณ , ๋ค๋ฅธ ๋ฐฐ์ด๊ณผ๋ ๋ ๋ฆฝ์ ์ผ๋ก ๋ถ์ฌ๋ ์ ์๋ค.
๋๊ฐ์ key๋ฅผ ๊ฐ์ ๋ฐฐ์ด์์๋ง ํ ๋นํ์ง ์๊ณ , ๋ค๋ฅธ ๋ฐฐ์ด์์๋ ์ฌ์ฌ์ฉํด๋ ๊ด์ฐฎ๋ค. ๊ณ ์ ์ฑ์ ํ์ ์ฌ์ด์์๋ง ์ ์ง๋๋ฉด ๋๊ธฐ ๋๋ฌธ์ด๋ค.
๊ฐ๊ฐ์ ์์๋ค์๊ฒ ๊ณ ์ ์ฑ์ ๋ถ์ฌํ๊ธฐ ์ํด key๋ฅผ ์ค์ ํ๋ ๊ฑด ์ดํดํ๋ค. ํ์ง๋ง ์ ๋ฐฐ์ด์ ์์๋ค ์ฌ์ด์์ ๊ณ ์ ์ฑ์ด ํ์ํ ๊น?
์ด๋ฅผ ์ดํดํ๊ธฐ ์ํด ๋จผ์ ๋ฆฌ์กํธ์ ์ฌ์กฐ์ ์ ๊ดํด ์์์ผ ํ๋ค.
React๋ virtual DOM์ ์ฌ์ฉํ์ฌ ์ค์ DOM์ ์ ๋ฐ์ดํธ ํ๋๋ฐ, ๋ณ๊ฒฝ ์ฌํญ ๋ฑ์ ํ์ธํด ํ์ํ ๋ถ๋ถ๋ง ์ ๋ฐ์ดํธํ๋ค.
์ด ๊ณผ์ ์ด ์ฌ์กฐ์ ์ด๋ค. ์ฌ์กฐ์ ์ด ์ค์ DOM ์๋ฆฌ๋จผํธ๋ฅผ ํต์งธ๋ก ์ ๋ฐ์ดํธ ํ๋ ๊ฒ๋ณด๋ค ๋๋ถ๋ถ ํจ์จ์ ์ด๊ธฐ ๋๋ฌธ์ ์ฐ๋ฆฌ๋ ๋ฆฌ์กํธ๋ฅผ ์ฌ์ฉํ๋ค.
์ถํ์ ๋ค๋ฅธ ํฌ์คํธ์์ ๋ค๋ฃจ๊ฒ ์ง๋ง ์ฌ์กฐ์ ์ ๋ถ๋ชจ๋ถํฐ ์์ํด ์์๋ค์ ์ฌ๊ท์ ์ผ๋ก ์ฒ๋ฆฌํ๋ค.
<ul>
<li>first</li>
<li>second</li>
</ul>
<ul>
<li>first</li>
<li>second</li>
<li>third</li>
</ul>
๋ค์๊ณผ ๊ฐ์ด ๋์ li๋ฅผ ์ถ๊ฐํ๋ ๊ฑด ๋ฆฌ์กํธ์์ ํจ์จ์ ์ผ๋ก ์ฒดํฌํ ์ ์๋ค.
first, second๋ฅผ ๋ชจ๋ ์ฌ๊ท์ ์ผ๋ก ์ํํ ๊ฒฐ๊ณผ ์ด์ ๊ฐ๊ณผ ๋์ผํ๊ธฐ ๋๋ฌธ์ ๋ณ๊ฒฝ์ ์ธ third๋ง ์ถ๊ฐํ๊ณ ์ฌ์กฐ์ ์ ์๋ฃํ๋ค.
<ul>
<li>Duke</li>
<li>Villanova</li>
</ul>
<ul>
<li>Connecticut</li>
<li>Duke</li>
<li>Villanova</li>
</ul>
ํ์ง๋ง ๋ค์๊ณผ ๊ฐ์ด ์์ ์ถ๊ฐํ๋ ๊ฒฝ์ฐ๋ ์ด๋จ๊น?
Duke๋ Connecticut๊ณผ ๋ค๋ฅด๋ค. Villanova ๋ํ Duke์ ๋ค๋ฅด๋ค. ์ด๋ ๋ฆฌ์กํธ๋ li๋ฅผ ์ฌ์ฌ์ฉํ์ง ๋ชปํ๊ณ ๋ด๋ถ ์์๋ค์ ํต์งธ๋ก ๋ฐ๊ฟ ์๋ฐ์ ์๋ค.
์ด๋ฐ ์ํฉ์ ๊ฐ์ ํ๊ธฐ ์ํด ๋์จ ๋ฐฉ๋ฒ์ด key์ด๋ค!
<ul>
<li key="2015">Duke</li>
<li key="2016">Villanova</li>
</ul>
<ul>
<li key="2014">Connecticut</li>
<li key="2015">Duke</li>
<li key="2016">Villanova</li>
</ul>
๋ค์๊ณผ ๊ฐ์ด key๋ฅผ ๋ถ์ฌํ๋ฉด ๋ฆฌ์กํธ๋ ํค๋ฅผ ๋น๊ตํ๋ฉฐ ์ฌ์กฐ์ ๊ณผ์ ์ ๊ฑฐ์น๋ค.
์์ ๊ฐ์ ์์์์๋ 2014๋ผ๋ ์๋ก์ด ํค๋ฅผ ๊ฐ์ง ์์๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ผ๋ก ์ฌ์กฐ์ ์ด ์๋ฃ๋๋ค.
๊ทธ๋ฐ๋ฐ ๊ณ ์ ํ ๊ฐ์ด๋ผ๋ฉด ๊ทธ๋ฅ ์ธ๋ฑ์ค๋ฅผ ์ฌ์ฉํด๋ ๋์ง ์์๊น? ์ id๋ผ๋ ๊ณ ์ ํ ์์ฑ์ ์ถ์ฒํ ๊น?
๋ฆฌ์กํธ๋ index๋ฅผ key๋ก ์ฌ์ฉํ๋ ๊ฑธ ๋ง๋ฆฌ๊ณ ์๋ค.
๊ทธ ์ด์ ๋ฅผ ํ๋ฒ ์์๋ณด์
์ง๊ธ๋ถํฐ๋ Index as a key is an anti-pattern๋ฅผ ์ฐธ์กฐํ๋ฉฐ ์์ฑํ๋ค.
๋ฆฌ์กํธ๋ key๋ฅผ ์ด์ฉํด DOM ์์๋ฅผ ์๋ณํ๋ค. ๊ทธ๋ฐ๋ฐ ์ด Key๊ฐ index์ด๊ณ ์๋ก์ด ์์๊ฐ ์์ชฝ์ ์ฝ์ ๋๋ ํํ๋ผ๋ฉด?
๋ฆฌ์กํธ๋ ์๋กญ๊ฒ ๋ค์ด์จ 0๋ฒ ์ธ๋ฑ์ค ์์๊ฐ ์๋ก์ด ์์๋ผ๊ณ ์ธ์ํ์ง ๋ชปํ๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ๋ด๋ถ์ ๊ฐ์ ์ปจํ ์ธ ๋ฅผ ๋ ๋๋งํ๊ฒ ๋๋ค.
๋ง๋ก๋ง ํด์๋ ์ ์ดํด๊ฐ ๋์ง ์๋๋ค. ์์๋ฅผ ํตํด ์ดํด๋ณด์.
const TodoExample = () => {
let id = useRef(2);
const [todos, setTodos] = useState([
{
id: 1,
content: "study",
},
{
id: 2,
content: "coding",
},
]);
const handleClick = () => {
const newTodos = [...todos];
newTodos.unshift({
id: ++id.current,
content: `new Item`,
});
setTodos(newTodos);
};
return (
<>
<button onClick={handleClick}>Add Todo</button>
<ul>
{todos.map((item, index) => (
<li key={index}>
<span>{item.id}</span>
<span>{item.content}</span>
<input type='text' defaultValue={item.content} />
</li>
))}
</ul>
</>
);
};
์์๊ณผ ๋ค๋ฅธ ๊ฒฐ๊ณผ๊ฐ ๋์จ๋ค!
์ด๋ ๊ฒ ๋ธ๋ผ์ฐ์ ๊ฐ ์์ ๋ฐ์ ๋ ๋๋ง์ ๋ถ๋ฌ์จ๋ค๋ ๊ฒ ์ธ์๋ ๋ค๋ฅธ ๋ฌธ์ ๊ฐ ์๋ค.
const handleClick = () => {
const newTodos = [...todos];
newTodos.unshift({
id: ++id.current,
content: `new Item`,
});
setTodos(newTodos);
};
return (
<>
<button onClick={handleClick}>Add Todo</button>
<ul>
{todos.map((item, index) => (
<li key={index}>{item.content}</li>
))}
</ul>
</>
);
ํ์ธ์ ์ํด ์ฝ๋๋ฅผ ์กฐ๊ธ ๊ฐ์ํํ๋ค.
๊ฐ๋ฐ์ ๋๊ตฌ๋ฅผ ํตํด ํ์ธํด๋ณด๋ฉด index๋ฅผ ํค ๊ฐ์ผ๋ก ์ค์ ํ์ ๋ ์ถ๊ฐ๋ ๋๋ง๋ค ๋ชจ๋ ์๋ฆฌ๋จผํธ๊ฐ ๋ฆฌ๋ ๋๋ง๋๋ ๊ฑธ ํ์ธํ ์ ์๋ค.
์ด๋ key๋ฅผ item.id๋ก ๋ฐ๊พธ๋ฉด ์ด๋จ๊น?
๋ณด์ด๋ ๊ฒ๊ณผ ๊ฐ์ด ์๋กญ๊ฒ ์ถ๊ฐ๋๋ ์์๋ง ๋ ๋๋ง๋๋ ๊ฑธ ๋ณผ ์ ์๋ค.
If you choose not to assign an explicit key to list items then React will default to using indexes as keys.
์ฐธ๊ณ ๋ก key๋ฅผ ๋ช ์์ ์ผ๋ก ์ง์ ํ์ง ์์ผ๋ฉด ๋ฆฌ์กํธ๋ index๋ฅผ key๋ก ์ค์ ํ๋ค.