React : useState에서 객체 배열의 값을 업데이트 할 때 새 객체의 새 배열을 만들자는 이야기

17437 단어 React
React의 useState에서 빠져서 메모.

요약



제목 긴.
- useState에서 객체의 배열을 관리 할 때 생각했듯이 값을 업데이트 할 수 없어서 빠졌습니다.
- useState로 배열을 갱신할 때는 새로운 배열을 만들어야 한다
- useState로 객체를 업데이트할 때는 새로운 객체의 배열을 만들어야 한다.
- useState에서 객체의 배열을 업데이트 할 때 새 객체의 새 배열을 만들어야합니다.

샘플



이런 TodoList를 만들어 change를 누르면 true/false가 바뀌도록 하고 싶다.


좋은 예 1



change를 눌러도 아무것도 변하지 않는다.
htps : // 코데씨 d보 x. 이오/s/인테페겐 t-조아나우4298?ぃぇ=/src/아 p. js
import { useState } from "react";

export default function App() {
  let [items, updateItems] = useState([
    { name: "item 1", done: false },
    { name: "item 2", done: true },
    { name: "item 3", done: false }
  ]);

  return (
    <div>
      <h2>Todo list</h2>
      <ul>
        {items.map((item, idx) => {
          return (
            <li key={idx}>
              <span>{`${item.name} ${item.done} `}</span>
              <button
                onClick={() => {
                  updateItems((oldItems) => {
                    oldItems[idx].done = !oldItems[idx].done;
                    return oldItems;
                  });
                }}
              >
                change
              </button>
            </li>
          );
        })}
      </ul>
    </div>
  );
}

안 좋은 예 2: 새로운 배열을 만들어 보자



과연, 아무래도 새로운 배열을 만들지 않으면 React에 변경이 전해지지 않고 update가 달리지 않는 것 같다.
htps : // m / 10 / 8 / ms / 896df09, d89, 41d48, c

그래서 새로운 배열을 만들어 본다.
h tps : // 코데 씨 d 보 x. 이오/s/아지타테 d-조아나-4kj4s?ぃぇ=/src/아 p. js
              <button
                onClick={() => {
                  updateItems((oldItems) => {
                    oldItems[idx].done = !oldItems[idx].done;
                    return [...oldItems];  // 新しい配列
                  });
                }}
              >
                change
              </button>

하지만 처음 1회만 바뀌어도 앞으로는 움직이지 않는다...

안 좋은 예 그 3: 새로운 객체를 만들어 보자



객체의 방향을 변경해야 할까 생각 이번에는 배열 내부의 객체를 변경하기로 한다
htps : // 코데씨 d보 x. 이오/s/스에에 t-ゔぃsゔぇsゔ아라야-7yr4s?ぃぇ=/src/아 p. js
              <button
                onClick={() => {
                  updateItems((oldItems) => {
                    // 新しいオブジェクトを作成
                    oldItems[idx] = {
                      ...oldItems[idx],
                      done: !oldItems[idx].done
                    };
                    return oldItems;
                  });
                }}
              >
                change
              </button>

하지만 움직이지 않는다.

좋은 예 : 새로운 객체를 만들어 새로운 배열에 밀어 넣습니다.



이것으로 생각했던 대로 움직였다.
              <button
                onClick={() => {
                  updateItems((oldItems) => {
                    return oldItems.map((oldItem, oldIdx) => {
                      if (oldIdx === idx) {
                        return { ...oldItem, done: !oldItem.done };
                      }
                      return oldItem;
                    });
                  });
                }}
              >
                change
              </button>

왜 잘못 됐는지



React 내부에서는 Object.is 를 사용해 비교하고 있는 것 같다.
htps : // 그럼. Rea ctjs. 오 rg / 두 cs / 호오 ks - 레후 렌세. html
htps : //로 ゔぇぺぺr. 모잖아. 오 rg / 쟈 / ㅇ cs / ぇ b / 쟈 ゔ Sc 리 pt / 레후 렌세 / G ぉ 바 l_ 오지 cts / 오 b ct / s # sc p

Object.is의 결과를 표시해 보면 다음과 같이 되었다.
              <button
                onClick={() => {
                  updateItems((oldItems) => {
                    console.log(
                      "新しい配列の中に古いオブジェクト:",
                      Object.is(items, [...oldItems]),
                      Object.is(items[idx], [...oldItems][idx])
                    ); // false, true
                    oldItems[idx] = {
                      ...oldItems[idx],
                      done: !oldItems[idx].done
                    };
                    console.log(
                      "古い配列の中に新しいオブジェクト",
                      Object.is(items, oldItems),
                      Object.is(items[idx], oldItems[idx])
                    ); // true, true

                    const newItems = oldItems.map((oldItem, oldIdx) => {
                      if (oldIdx === idx) {
                        return { ...oldItem, done: !oldItem.done };
                      }
                      return oldItem;
                    });
                    console.log(
                      "新しい配列の中に新しいオブジェクト",
                      Object.is(items, newItems),
                      Object.is(items[idx], newItems[idx])
                    ); // false, false

                    return newItems;
                  });
                }}
              >
                change
              </button>

배열내의 오브젝트를 내부에서 한층 더 어떻게 비교하고 있는지까지는 조사되지 않았지만, 배열 자체도 오브젝트 자체도 Object.is가 false가 되지 않으면 안 되는 것 같다.

이해에 실수, 보다 좋은 쓰는 방법등 있으면 가르쳐 주세요 🙇‍♂️

좋은 웹페이지 즐겨찾기