Nebezpečí používání objektu v ReactJS Hooks

Tento článek napsal náš generální ředitel a vývojář Tiago Duarte

Háčky existují již téměř dva roky. Jsou přidány v Reactu v16.8.0 a umožňují vám používat stav a další funkce Reactu, aniž byste museli psát třídu.

V tomto článku se nebudeme moc podrobně zabývat tím, co je háček, jeho syntaxí a tak dále a tak dále. Za tímto účelem můžete navštívit stránku s dokumentací Reactu, kde si myslíme, že tým React odvedl skvělou práci 👍🏾 a nedokázali jsme to vysvětlit lépe.

(Ne)známý problém používání objektů v useState / useEffect hook

To, co nás sem přivádí, je problém/chyba 🐞, se kterou jsme se potýkali, když jsme poprvé začali používat háky, a která může snadno zůstat bez povšimnutí.

Podívejme se na následující příklad:

const { useState } = React;

const Counter = () => {
  const [count, setCount] = useState(0);
  const [objectCount, setObjectCount] = useState({ count: 0 });

  return (
    <div>
      <h2>Count</h2>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Increase normal count</button>

      <h2>Object Count</h2>
      <p>You clicked {objectCount.count} times</p>
      <button
        onClick={() => {
          objectCount.count += 1;
          setObjectCount(objectCount);
        }}
      >
        Broken increase of the object count
      </button>

      <br />
      <br />

      <button
        onClick={() =>
          setObjectCount({
            ...objectCount,
            count: objectCount.count + 1,
          })
        }
      >
        Functioning increase of the object count
      </button>
    </div>
  );
};

ReactDOM.render(<Counter />, document.getElementById('app'));

Připravili jsme tento kodex s příkladem, můžete jej navštívit a pohrát si s ním.

V našem příkladu máme:

  • a count státní háček, který ukládá obyčejné číslo

  • objectCount state hook, který ukládá objekt obsahující vlastnost count uvnitř

  • "Increase normal count" tlačítko, které aktualizuje count Stát. Můžete to ověřit tím, že uvidíte, že se počítadlo aktualizuje ihned po stisknutí tlačítka

  • a "Broken increase of the object count" tlačítko, které se pokouší aktualizovat objectCount , ale nešťastně selže 🙀. Možná si říkáte „naaaaaahhh, to by mělo fungovat…“. Pokračujte a vyzkoušejte to na codepen

  • "Functioning increase of the object count" tlačítko, které správně aktualizuje objectCount Stát

Proč stisknout "Broken increase of the object count" nezvýší okamžitě počet objektů?

Když uživatel stiskne tlačítko, zvýšíme count vlastnost uvnitř objectCount objekt a poté zavolejte setObjectCount(objectCount) .

Problém je v tom, že useState hook používá přísné porovnání rovnosti k určení, zda má spustit opětovné vykreslení, a nekontroluje, zda se vlastnosti objektu skutečně změnily.

Jinými slovy, hák porovnává (=== ) stav „starý“ a „nový“ a dojde k závěru, že se objekt nezměnil a nespustí opětovné vykreslení, což způsobí, že označení počtu objektů zůstane stejné😭.

Možná řešení

Vytvořte a předejte mělkou kopii do setObjectCount

“Functioning increase of the object count” tlačítko opravuje problém vytvořením a předáním mělké kopie objectCount na funkci setter.

V zásadě zachovává stejné vlastnosti objektu, ale vytváří novou referenci na objekt, takže porovnání přísné rovnosti háčků určí, že se stav změní, a okamžitě spustí opětovné vykreslení.

Nepoužívejte objekt jako stav

Dalším řešením by bylo jednoduše nepoužívat objekty v useState háček.

Můžete použít useState háček pro každou vlastnost objektu. Teoreticky by to byl ideální scénář, ale udělat to může být skličující a časově náročné.

Možná máte důvody k přímému uložení objektu jako stavu. V našem případě jsme získávali data z API a rozhodli jsme se načtený objekt uložit 🤭.

Použijte háček useReducer

Pokud znáte Redux, už víte, jak to funguje, protože je velmi podobný.

useReducer akceptuje redukci typu (state, action) => newState a vrátí aktuální stav spárovaný s dispatch metoda.

Toto je obvykle vhodnější než useState když máte složitou stavovou logiku, která zahrnuje více dílčích hodnot, nebo když další stav závisí na předchozím.

Použijte immutable.js

Podle dokumentace:

Prakticky řečeno, při použití immutable.js by každá změna objektu ve skutečnosti vytvořila nový objekt. V našem příkladu by to způsobilo, že stavový hák spustí opětovné vykreslení.

Úspora času

Když se tento problém stal mně a Rui Sousovi, strávili jsme, řekl bych, pár hodin hledáním problému. Proto jsme chtěli sdílet tento tip v naději, že vám ušetří čas při ladění!

Pokud máte návrh nebo jiné řešení, než jsou uvedeny, neváhejte a zanechte nám komentář 💬. Jsme velmi přátelští, slibujeme 😇.

Reference

  • Háčky na první pohled

  • Pomocí State Hook

  • Použití efektového háčku

  • MDN — Srovnání rovnosti a stejnosti

  • Porozumění Deep and Shallow Copy v Javascriptu

  • Raquel Pontes mi nedovolila použít původní ilustraci obálky 😢, takže ji nechám zde pro budoucí použití:



Děkujeme za přečtení!

Moc děkujeme za přečtení, moc to pro nás znamená! Nezapomeňte také sledovat Coletiv na Twitteru a LinkedIn jak neustále zveřejňujeme stále více zajímavých článků o různých technologiích.

V případě, že nevíte, Coletiv je studio pro vývoj softwaru z Porta, které se specializuje na vývoj Elixir, webu a aplikací (iOS a Android). Ale děláme všelijaké věci. Postaráme se o návrh UX/UI, vývoj softwaru a dokonce i zabezpečení.

Takže vytvoříme něco společně?