๐Ÿ”‘ ๋ฆฌ์ŠคํŠธ์™€ Key in React

Lee Jooamยท2022๋…„ 5์›” 12์ผ
0

๋ฆฌ์ŠคํŠธ ๋ Œ๋”๋ง ํ•˜๊ธฐ

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

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์˜ ์—ญํ• 

๊ฐ๊ฐ์˜ ์š”์†Œ๋“ค์—๊ฒŒ ๊ณ ์œ ์„ฑ์„ ๋ถ€์—ฌํ•˜๊ธฐ ์œ„ํ•ด 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๋ผ๋Š” ์ƒˆ๋กœ์šด ํ‚ค๋ฅผ ๊ฐ€์ง„ ์š”์†Œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์žฌ์กฐ์ •์ด ์™„๋ฃŒ๋œ๋‹ค.

index๋ฅผ Key๋กœ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด?

๊ทธ๋Ÿฐ๋ฐ ๊ณ ์œ ํ•œ ๊ฐ’์ด๋ผ๋ฉด ๊ทธ๋ƒฅ ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•ด๋„ ๋˜์ง€ ์•Š์„๊นŒ? ์™œ 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๋กœ ์„ค์ •ํ•œ๋‹ค.

profile
ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž๋กœ ๊ฑธ์–ด๊ฐ€๋Š” ์ค‘์ž…๋‹ˆ๋‹ค.

0๊ฐœ์˜ ๋Œ“๊ธ€