React - problem z tablicą w stanie

0

Mam coś takiego:

const [products, setProducts] = React.useState(); // products to tablica obiektów, np. [{a:1,b:2},{a:3,b:4}]

chciałbym teraz dodać do każdego obiektu w products dynamicznie nową parę klucz-wartość, która będzie początkowo taka sama dla wszystkich, np. c: 5, którą przypisywałem w taki sposób:

products.map((element) => (
element.c = 5;
);

a następnie w useEffect w zależności sprawdzać, kiedy ten nowy klucz się zmienia

React.useEffect(() => {
    // kod który coś robi
  }, [...products.map((item) => item.c)]);

wartość klucza nadpisywałem w innym miejscu tym samym sposobem, którym dodawałem klucz, czyli:

products.map((element) => (
element.c = 999;
);

niestety powyższe zdaje się nie działać, useEffect nie wyłapuje zmian, a ja nie do końca wiem gdzie leży błąd. Byłbym wdzięczny za pomoc.

1

Bo React musi wiedzieć, że coś się zmieniło. Robiąc coś takiego

products.map((element) => (
element.c = 5;
);

zmieniasz ręcznie tablicę. Więc React o tym nie wie. I po to jest setter setProducts:

setProducts(products.map(element => ({ ...element, c: 5 }));

a dlaczego ({ ...element, c: 5}) zamiast element.c = 5? Żeby nie mutować(nie zmieniać) istniejących obiektów, tylko stworzyć dla każdego obiektu kopię.

0

Dzięki za odpowiedź. Niestety nie pomaga mi to, ponieważ dostaję błąd:

Warning: The final argument passed to useEffect changed size between renders. The order and size of this array must remain constant.

Previous: []
Incoming: [1]

Wskazywałoby to na to, że w ogóle nie da się zrobić podobnej operacji na obiektach? Czy można do tego podejść inaczej?

1
const [products, setProducts] = React.useState([
    { a: 1, b: 2 },
    { a: 3, b: 4 }
  ]);

  React.useEffect(() => {
    // kod który coś robi
    console.log("hello");
  }, [products]);

return (
    <>
      <button onClick={() => setProducts([...products, { c: 999 }])}>
        Test
      </button>
      {products.map((el) => (
        <p>{Object.entries(el)}</p>
      ))}
    </>
)

O ile dobrze rozumiem, to chyba taki jest cel? Jezeli zmieniasz klucz w innym miejscu to musisz wywolac rowniez setProducts w ten sam sposob jak powyzej na buttonie.

0

Zbadałem problem dogłębniej, i wbrew temu co wcześniej pisałem, nie leży tam gdzie myślałem, tylko ma coś wspólnego z działaniem kontekstu.
W apce wartości products i setProducts przesyłam w kontekście do innych plików, tak że:

  • ustawienie kontekstu jest w pliku A
  • pobranie danych z kontekstu, fetch obiektu do products i dodanie nowego klucza 'c' z wartością jest w pliku B
  • pobranie danych z kontekstu i update wartości klucza 'c' jest w pliku C
  • pobranie danych z kontekstu i render wartości klucza 'c' jest w pliku A

Błąd o którym wcześniej pisałem pojawia się tylko przy używaniu i przekazywaniu danych do kontekstu, w jednym pliku poniższa logika działa poprawnie.

const Temp = () => {
  const [products, setProducts] = React.useState([
    { a: 1, b: 2 },
    { a: 3, b: 4 },
  ]);
  const [totalC, setTotalC] = React.useState(0);

  function addC() {
    setProducts(products.map((el) => ({ ...el, c: 1 })));
  }

  function changeC() {
    setProducts(products.map((el) => ({ ...el, c: el.c + 1 })));
  }

  function updateC() {
    let tempC = 0;
    products.map((el) => {
      tempC = tempC + el.c;
    });
    setTotalC(tempC);
  }

  React.useEffect(() => {
    updateC();
  }, [...products.map((el) => el.c)]);

  return (
    <>
      <button onClick={() => addC()}>Add C</button>
      <button onClick={() => changeC()}>Change C</button>
      <span>Wartość c: {totalC}</span>
    </>
  );
};

Nie mam pomysłu dlaczego kontekst psuje działanie logiki.

1 użytkowników online, w tym zalogowanych: 0, gości: 1