ํ‹ฐ์Šคํ† ๋ฆฌ ๋ทฐ

๊ฐ€์žฅ ํ”ํ•˜์ง€๋งŒ ์•Œ์ฐจ๊ณ  ๊ธฐ๋ณธ๊ธฐ๋ฅผ ์ตํžˆ๊ธฐ์— ์ข‹์€ ๊ฒƒ ๊ฐ™์€ ํˆฌ๋‘๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฆฌ์•กํŠธ๋กœ ๋งŒ๋“ค์–ด๋ณด์•˜๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ๋Š” ๊ทธ๋™์•ˆ 2-3๋ฒˆ ์ •๋„ ๋งŒ๋“ค์–ด๋ณธ ๊ฒƒ ๊ฐ™์€๋ฐ..๐Ÿค”
๋ฆฌ์•กํŠธ๋กœ๋Š” ๊ฐ•์˜ ๋”ฐ๋ผ ์นœ ๊ธฐ์–ต๋งŒ ๋‚˜๊ณ  ํ˜ผ์ž ํž˜์œผ๋กœ๋Š” ๋งŒ๋“ค์–ด๋ณธ ๊ธฐ์–ต์ด ์—†๋Š” ๊ฒƒ ๊ฐ™์•˜๋‹ค.
์ด๋ ‡๊ฒŒ ๋œ๊ฑฐ ๊ฐ„๋‹จํ•œ ํˆฌ๋‘ ์•ฑ์„ ๋งŒ๋“ค๋ฉด์„œ ๋ฆฌ์•กํŠธ ๊ธฐ๋ณธ๊ธฐ๋ฅผ ๋‹ค์‹œ ์žก๊ณ  ์‹ถ๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค!

๐ŸŽจ ๋””์ž์ธ

๊ธฐ๋Šฅ ๊ตฌํ˜„์ด ๋” ์ค‘์š”ํ•œ ๊ฒƒ ๊ฐ™์•„์„œ ๋””์ž์ธ์€ ์ดˆ์ดˆ์ดˆ ๊น”๋”ํ•˜๊ฒŒโœจ ํ•ด์•ผ์ง€ ์ƒ๊ฐํ–ˆ๋‹ค.
ํ”ผ๊ทธ๋งˆ๋ฅผ ์ž˜ ๋‹ค๋ฃจ์ง€๋Š” ๋ชปํ•˜์ง€๋งŒ ์•„์˜ˆ ๋ชจ๋ฅด๋Š” ๊ฑด ์•„๋‹ˆ๊ธฐ์— ํ”ผ๊ทธ๋งˆ๋ฅผ ์ด์šฉํ•ด ๋””์ž์ธ ์‹œ์•ˆ์„ ์žก์•„๋ณด์•˜๋‹ค.
(์—ฌ๋ฐฑ์˜ ๋ฏธ-!ใ…Žใ…Žใ…Ž)

โš™๏ธ ๊ธฐ๋Šฅ

๊ธฐ๋Šฅ ๊ตฌํ˜„์— ์•ž์„œ์„œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ธฐ๋Šฅ๋ณ„๋กœ ๋‚˜๋ˆ„์–ด ์ฃผ์—ˆ๋‹ค.
๊ณตํ†ต ์ปดํฌ๋„ŒํŠธ (๋ฒ„ํŠผ, input)๋ฅผ ๋งŒ๋“ค๊นŒ ์ƒ๊ฐํ–ˆ๋Š”๋ฐ ์—ฌ๊ธฐ์—์„œ๋Š” ๊ทธ์ •๋„๊นŒ์ง„ ํ•„์š”ํ•˜์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™๋‹ค๊ณ  ํŒ๋‹จํ–ˆ๋‹ค.
๋ฐ˜๋ณตํ•ด์„œ ์‚ฌ์šฉํ• ๋งŒํ•œ๊ฒŒ ๋ฒ„ํŠผ๋ง๊ณ ๋Š” ์—†๋Š”๋“ฏํ•œ..?ใ…Žใ…Ž
๊ทธ๋ž˜์„œ ๊ทธ๋ƒฅ ์œ„์™€ ๊ฐ™์ด ๊ธฐ๋Šฅ๋ณ„๋กœ ๋‚˜๋ˆ„์–ด์ฃผ์—ˆ๋‹ค. ์—ฐ์Šตํ•˜๋Š”๊ฑฐ๋‹ˆ๊นŒ ๊ฐ€๋ณ๊ฒŒํ•˜์ž!

๋“ฑ๋กํ•˜๊ธฐ

๋“ฑ๋ก ๊ธฐ๋Šฅ์€ ๋“ฑ๋ก ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ๋•Œ ํ• ์ผ์ด ์ถ”๊ฐ€๋˜๋„๋ก ๊ตฌํ˜„ํ–ˆ๋‹ค.

๐Ÿ“ ํ•  ์ผ ๋“ฑ๋ก๊ณผ์ •

  1. input์— onChange์ด๋ฒคํŠธ๊ฐ€ ์ผ์–ด๋‚  ๋•Œ๋งˆ๋‹ค ๊ทธ ๊ฐ’์„ setInputValueํ•จ์ˆ˜์— ๋„ฃ์–ด useState๋กœ ๊ด€๋ฆฌํ•œ๋‹ค.

    const onChangeInput = (e) => {
     const { value } = e.target;
     setInputValue(value);
    };
  2. ๋“ฑ๋ก ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ, ์ž…๋ ฅํ•œ ๊ฐ’์ด ์žˆ๋‹ค๋ฉด setTodoListํ•จ์ˆ˜์— ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฐ์ฒดํ˜•ํƒœ์˜ todo๋ฅผ ๋„ฃ์–ด useState๋กœ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•ด์ฃผ๋„๋ก ํ•œ๋‹ค.

    const [todoList, setTodoList] = useState([]);
    const [todoId, setTodoId] = useState(0);
    
    const onClickAddTodo = () => {
     if (inputValue) {
       setTodoList((prev) => [
         ...prev,
         {
           id: todoId,
           text: inputValue,
           done: false,
           isUpdating: false,
         },
       ]);
       setTodoId((prev) => prev + 1);
       setInputValue("");
     }
    };
  3. todoList ์ƒํƒœ๊ฐ€ ์—…๋ฐ์ดํŠธ ๋  ๋•Œ๋งˆ๋‹ค ํ•ด๋‹น ๊ฐ’์„ localStorage์— ์ €์žฅํ•ด์ค€๋‹ค.

    useEffect(() => {
     localStorage.setItem("todoListData", JSON.stringify(todoList));
    }, [todoList]);
  4. ์ตœ์ดˆ ๋ Œ๋”๋ง ์‹œ, ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅ๋œ ํˆฌ๋‘๋ฆฌ์ŠคํŠธ๋ฅผ ๊ฐ€์ ธ์™€์„œ ์ถœ๋ ฅํ•ด์ค€๋‹ค.

    useEffect(() => {
     const localTodoList = localStorage.getItem("todoListData");
     if (localTodoList) {
       setTodoList(JSON.parse(localTodoList));
     }
    }, []);

์ˆ˜์ •ํ•˜๊ธฐ

๐Ÿ“ ํ•  ์ผ ์ˆ˜์ •๊ณผ์ •

  1. ์ˆ˜์ • ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ todo์˜ id์™€ ์ˆ˜์ • ๋ฒ„ํŠผ์ด ๋ˆŒ๋ฆฐ todo์˜ id๊ฐ€ ๊ฐ™๋‹ค๋ฉด, todoList ๊ฐ์ฒด์—์„œ isUpdating์„ ture๋กœ ๋ฐ”๊พธ์–ด์ค€๋‹ค.

    const onEdit = (id) => {
     setTodoList(
       todoList.map((todo) =>
         todo.id === id ? { ...todo, isUpdating: !todo.isUpdating } : todo
       )
     );
    };
  2. ์ˆ˜์ • ์ค‘์ธ ์ƒํƒœ๊ฐ€ ๋˜๋ฉด todoItem์ด span์—์„œ input์œผ๋กœ ๋ณ€๊ฒฝ๋œ๋‹ค.
    ์ด๋•Œ, input์˜ value๋Š” ์›๋ž˜ ์ž…๋ ฅ๋˜์—ˆ๋˜ ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์•ผ ํ•˜๊ณ  ์ˆ˜์ •์„ ํ†ตํ•ด ๋ณ€๊ฒฝ๋˜์–ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— useState๋ฅผ ํ†ตํ•ด ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋„๋ก ํ•œ๋‹ค.

const [newText, setNewText] = useState(text);
{isUpdating ? (
  <input
    type="text"
    onKeyDown={(e) => onEnterEdit(e, id)}
    onChange={(e) => onChangeEditInput(e)}
    value={newText}
    className="updateTodoInput"
  ></input>
) : (
  <span className={done ? "checked checkedText" : ""}>{text}</span>
)}
  1. input์—์„œ onChange ์ด๋ฒคํŠธ๊ฐ€ ์ƒ๊ธฐ๋ฉด ํ•ด๋‹น ๊ฐ’์„ setNewTextํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์ƒˆ๋กœ์šด ๊ฐ’์˜ ์ƒํƒœ๋กœ ์—…๋ฐ์ดํŠธ ์‹œ์ผœ ๊ด€๋ฆฌํ•œ๋‹ค.

    const onChangeEditInput = (e) => {
     setNewText(e.target.value);
    };
  2. ์ˆ˜์ • ํ›„ ์—”ํ„ฐ๋ฅผ ๋ˆ„๋ฅด๋ฉด onKeyDown ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ , setTodoListํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด todoList ๊ฐ์ฒด์— text๊ฐ€ ์ƒˆ๋กœ์šด ํ…์ŠคํŠธ ๊ฐ’์œผ๋กœ ์—…๋ฐ์ดํŠธ๋˜๊ณ  ์ˆ˜์ • ์ค‘์ธ ์ƒํƒœ(isUpdating)๊ฐ€ false๋กœ ๋ณ€๊ฒฝ๋œ๋‹ค.

    const onEnterEdit = (e, id) => {
     if (e.key === "Enter") {
       setTodoList(
         todoList.map((todo) => {
           if (todo.id === id) {
             return { ...todo, text: newText, isUpdating: false };
           }
           return todo;
         })
       );
     }
    };
    

5. ์ถ”๊ฐ€๋กœ, ์ˆ˜์ •์ค‘์ผ ๋•Œ์—๋Š” โœ… ๋˜๋Š” โ˜‘๏ธ ์•„์ด์ฝ˜์ด ๋œจ์ง€ ์•Š๋„๋ก ํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์Œ์˜ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์˜€๋‹ค.
- ์ˆ˜์ • ์ค‘์ผ ๊ฒฝ์šฐ : ""
- ์ˆ˜์ • ์ค‘์ด ์•„๋‹ ๊ฒฝ์šฐ
  - ์™„๋ฃŒ ์ƒํƒœ๋ผ๋ฉด : โœ…
  - ์™„๋ฃŒ ์ƒํƒœ๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด : โ˜‘๏ธ

```jsx
<span
  className={done ? "checked" : ""}
  onClick={() => checkToggle(id)}
>
 {isUpdating ? "" : (done ? "โœ… " : "โ˜‘๏ธ ")}
</span>

์‚ญ์ œํ•˜๊ธฐ

ํ•  ์ผ ์‚ญ์ œ๊ณผ์ •

  1. ํ•  ์ผ์„ ์™„๋ฃŒํ•˜๋ฉด ์ฒดํฌ๋ฐ•์Šค๋ฅผ ํด๋ฆญํ•œ๋‹ค.
    todo์˜ id์™€ ์ฒดํฌ ๋ฒ„ํŠผ์ด ๋ˆŒ๋ฆฐ todo์˜ id๊ฐ€ ๊ฐ™๋‹ค๋ฉด, ํ•ด๋‹น todoItem์— ๋Œ€ํ•ด done ์ƒํƒœ๋ฅผ true๋กœ ๋ณ€๊ฒฝ์‹œํ‚จ๋‹ค.

    const checkToggle = (id) => {
     setTodoList(
       todoList.map((todo) => {
         if (todo.id === id) {
           return { ...todo, done: !done };
         }
         return todo;
       })
     );
    };
  2. ํ•  ์ผ์ด ์™„๋ฃŒ๋œ ์ƒํƒœ(done: true) ์ด๊ฑฐ๋‚˜ ์ˆ˜์ •์ค‘์ด๋ผ๋ฉด ์ˆ˜์ • ๋ฒ„ํŠผ์ด ๋‚˜ํƒ€๋‚˜์ง€ ์•Š๋„๋ก ํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์Œ์˜ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค.

    {done || isUpdating ? ( <></> ) : 
    ( <button onClick={() => onEdit(id)} className="todoitemBtn">
       ์ˆ˜์ •
     </button>
    )}
  3. ์‚ญ์ œ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ, ์‚ญ์ œ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅธ todoItem์˜ id๋ฅผ ์ œ์™ธํ•œ todoList๋ฅผ setTodoListํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธ ์‹œ์ผœ์ค€๋‹ค.

    const onRemove = (id) => {
     setTodoList(todoList.filter((todo) => todo.id !== id));
    };

ํˆฌ๋‘ ์นด์šดํŠธ ์„ธ๊ธฐ

์™„๋ฃŒ๋œ ํ•  ์ผ(done: true)๊ณผ ์•„์ง ์™„๋ฃŒ๋˜์ง€ ์•Š์€ ํ•  ์ผ(done: false)์— ๋Œ€ํ•ด ํ•„ํ„ฐ๋ง์„ ํ•˜์—ฌ ๊ทธ ๊ธธ์ด๋ฅผ ๋ณด์—ฌ์ฃผ๋„๋ก ํ–ˆ๋‹ค.

const unDoneTodoList = todoList.filter((todo) => !todo.done);
const doneTodoList = todoList.filter((todo) => todo.done);

<span>โ˜‘๏ธ {unDoneTodoList.length}๊ฐœ ๋‚จ์Œ </span>
<span>โœ… {doneTodoList.length}๊ฐœ ์™„๋ฃŒ</span>

๐Ÿ‘ฟ ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ…

[์˜ค๋ฅ˜1] - useState ์ดˆ๊ธฐํ™”๋กœ ์ธํ•œ ์˜ค๋ฅ˜

todo ๋“ฑ๋ก ์‹œ์— useState๋กœ ๊ด€๋ฆฌ๋˜๋Š” id ๊ฐ’์„ ํ•จ๊ป˜ ์ €์žฅํ•˜๋Š”๋ฐ ์—ฌ๊ธฐ์„œ ์˜ค๋ฅ˜๊ฐ€ ์ƒ๊ฒผ๋‹ค.

const [todoList, setTodoList] = useState([]);
const [inputValue, setInputValue] = useState("");
const [todoId, setTodoId] = useState(0);

const onClickAddTodo = () => {
    if (inputValue) {
      setTodoList((prev) => [
        ...prev,
        {
          id: todoId,
          text: inputValue,
          done: false,
          isUpdating: false,
        },
      ]);
      setTodoId((prev) => prev + 1);
      setInputValue("");
    }
};

์ตœ์ดˆ ๋ Œ๋”๋ง ํ›„ todo๋ฅผ ๋“ฑ๋กํ•˜๋ฉด ์ž˜ ๋˜๋Š”๋ฐ ์ƒˆ๋กœ๊ณ ์นจ์„ ํ•œ๋ฒˆ ํ•ด์ฃผ๋ฉด todo์˜ id ๊ฐ’์ด 0์œผ๋กœ ๋‹ค์‹œ ์ดˆ๊ธฐํ™”๊ฐ€ ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

๋‚ด๊ฐ€ ์ƒ๊ฐํ•œ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•์€ ์ด๋ ‡๋‹ค.

  1. todoList๋ฅผ ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฑฐ๊ธฐ์„œ id๊ฐ’์„ ๊ฐ€์ ธ์˜ค๊ธฐ
  2. todoList์˜ ๊ธธ์ด๋ฅผ id ๊ฐ’์œผ๋กœ ์“ฐ๊ธฐ
  3. id ๊ฐ’๋„ ๋”ฐ๋กœ ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅํ•˜๊ณ  ๊ฐ€์ ธ์™€์„œ ์‚ฌ์šฉํ•˜๊ธฐ
  4. Date.now() ์‚ฌ์šฉํ•˜๊ธฐ

1๋กœ ํ•ด๋ณผ๊นŒ ๊ณ ๋ฏผ์„ ํ–ˆ๋‹ค๊ฐ€...๐Ÿค” 3์€ id๊ฐ’์„ ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์— ๋„ฃ์–ด๋„ ๋˜๋Š”๊ฑด๊ฐ€? ๋ผ๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๊ณ 
2๋„ ๊ฐ™์€ ์˜ค๋ฅ˜๊ฐ€ ์ƒ๊ธฐ๋Š” ๊ฒƒ ๊ฐ™์•„์„œ 4๋ฒˆ์œผ๋กœ ์ตœ์ข… ๊ฒฐ์ •ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค.

๊ทผ๋ฐ ๋ญ”๊ฐ€ ์ฐœ์ฐœํ•˜๊ฒŒ ํ•ด๊ฒฐํ•œ ๊ธฐ๋ถ„์ด๋ผ ์ข€ ๋” ์•Œ์•„๋ด์•ผ๊ฒ ๋‹ค๐Ÿฅฒ

[์˜ค๋ฅ˜2] - input ์ž…๋ ฅ ์‹œ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ ๋ฆฌ๋ Œ๋”๋ง


input์— ํ•  ์ผ์„ ์ž…๋ ฅํ•  ๋•Œ ๋ชจ๋“  ์ˆœ๊ฐ„๋งˆ๋‹ค ๋ Œ๋”๋ง์ด ์ผ์–ด๋‚˜๋Š” ๊ฒƒ์„ ํ™•์ธํ–ˆ๋‹ค.
input์— ๋Œ€ํ•œ ์ตœ์ ํ™”...๐Ÿค” ๋””๋ฐ”์šด์Šค? ์ด๊ฑด ์•„๋‹Œ ๊ฒƒ ๊ฐ™๊ณ ..

๊ทธ๋Ÿฌ๋‹ค ๋ฌธ๋“ ๋ฆฌ์•กํŠธ๋ฅผ ์ฒ˜์Œ ๋ฐฐ์šธ ๋•Œ ๋“ค์—ˆ๋˜ ๊ฐ•์˜์—์„œ๋„ input ์ž…๋ ฅ ์‹œ ๋ Œ๋”๋ง์ด ์ผ์–ด๋‚˜๋Š” ์˜ˆ์ œ๋ฅผ ๋ณธ ๊ธฐ์–ต์ด ๋‚ฌ๋‹ค!! ์–ผ๋ฅธ ๊ทธ ๋‹น์‹œ ๋ฐฐ์šด ๊ต์žฌ๋ฅผ ๋‹ค์‹œ ์ฐพ์•„๋ณด์•˜๋Š”๋ฐ React.memo๋ฅผ ์“ฐ๋ฉด ๋œ๋‹ค๊ณ  ํ–ˆ๋‹ค.

React.memo

React.memo๋Š” ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ(Higher Order Component, HOC)๋กœ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋™์ผํ•œ props๋กœ ๋™์ผํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋ Œ๋”๋งํ•˜๋ฉด, React.memo๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ๋ฉ”๋ชจ์ด์ง•ํ•˜๋„๋ก ๋ž˜ํ•‘ํ•˜์—ฌ ๊ฒฝ์šฐ์— ๋”ฐ๋ผ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.
์ฆ‰, React๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ์žฌ๋ Œ๋”๋งํ•˜์ง€ ์•Š๊ณ  ๋งˆ์ง€๋ง‰์œผ๋กœ ๋ Œ๋”๋ง๋œ ๊ฒฐ๊ณผ๋ฅผ ์žฌ์‚ฌ์šฉํ•œ๋‹ค.

์ •๋ง ๊ฐ„๋‹จํ•˜๊ฒŒ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‚ด๋ณด๋‚ผ ๋•Œ React.memo๋กœ ๊ฐ์‹ธ์ฃผ๊ธฐ๋งŒ ํ•˜๋ฉด ๋๋‹ค.

{...์ฝ”๋“œ}
export default React.memo(CreateTodo);

๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ๋“ค๋„ ๋ชจ๋‘ React.memo๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์—ˆ๋‹ค.
์ด๋ ‡๊ฒŒ ๋˜๋ฉด ๊ฐ ์ปดํฌ๋„ŒํŠธ์˜ props ๋ฐ์ดํ„ฐ๋“ค์ด ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ๊ธฐ์กด์˜ ๊ฐ’์„ ๊ทธ๋Œ€๋กœ ์ถœ๋ ฅํ•ด์ค€๋‹ค.

๊ฒฐ๊ณผ


(์ฒ˜์Œ์— ๋ Œ๋”๋ง ์ฝ˜์†”์ด ๋‘๋ฒˆ ์ฐํžˆ๋Š” ๊ฒƒ์€ strict ๋ชจ๋“œ ๋•Œ๋ฌธ์ด๋‹ค.)

์ฝ˜์†”์ฐฝ์„ ๋ณด๋ฉด ์ž…๋ ฅํ•  ๋•Œ ๋ Œ๋”๋ง์ด ์ผ์–ด๋‚˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค!๐Ÿคฉ


๐Ÿ“š ์ฐธ๊ณ 

๋ฆฌ์•กํŠธ ๊ณต์‹๋ฌธ์„œ - React.memo
๋ฒจ๋กœํผํŠธ์™€ ํ•จ๊ป˜ํ•˜๋Š” ๋ชจ๋˜ ๋ฆฌ์•กํŠธ - 19. React.memo ๋ฅผ ์‚ฌ์šฉํ•œ ์ปดํฌ๋„ŒํŠธ ๋ฆฌ๋ Œ๋”๋ง ๋ฐฉ์ง€

๋Œ“๊ธ€