javascript - react hooks: Vad är nackdelen med att direkt ändra det nästlade objektet?


import { useState } from "react";

function App() {
  const [form, setForm] = useState({
    usename: ``,
    password: ``,
    avatar: { id: 0, url: ``, deep: { id: 0 } },
  });
  return (
    <div>
      <h1>ID:{form.avatar.deep.id}</h1>
      <h2
        onClick={() => {
          form.avatar.deep.id += 1;
          setForm({ ...form });
        }}
      >
        Change-ID
      </h2>
    </div>
  );
}

export default App;

codesandbox-online-kör

Jag lär mig riktiga krokar, folk säger till mig att inte ändra nästlade objekt.

Vi bör hålla det ursprungliga tillståndet oförändrat eller använda https://github.com/immerjs/immer

Men ovanstående kod kan också uppdatera användargränssnittet, varför?

Vilka är nackdelarna med form.avatar.deep.id+=1;setForm({ ...form }); ?

Vilka är nackdelarna med att ändra attributen hos det nästlade objektet direkt?

Svar #1

Vilka är nackdelarna med form.avatar.deep.id+=1;setForm({ ...form });?

React är designat med oföränderligt tillstånd i åtanke. Detta gör det möjligt att göra en mycket billig === jämförelse för att avgöra om saker har ändrats. Du har kopierat form, och det räcker för att få denna exempel kod att fungera. Den gamla och nya formen är olika objekt, så komponenten renderas om när du sätter state.

Problemet uppstår om någon del av koden bryr sig om en del av formuläret, inte hela formuläret. Om en komponent vill kontrollera om form.avatar har ändrats, kommer den att se att nej, det har inte ändrats, men i själva verket har det det!

Till exempel, anta att vi delar ut en Avatar-komponent på följande sätt:

import { memo } from 'react';

function App() {
  const [form, setForm] = useState({
    usename: ``,
    password: ``,
    avatar: { id: 0, url: ``, deep: { id: 0 } },
  });

  return (
    <div>
      <Avatar avatar={form.avatar} />
      <h2
        onClick={() => {
          form.avatar.deep.id += 1;
          setForm({ ...form });
        }}
      >
        Change-ID
      </h2>
    </div>
  );
}

const Avatar = memo(function ({ avatar }) {
  useEffect(() => {
    // Supposed to do some stuff, if avatar has changed
  }, [avatar]);

  return (
    <h1>ID:{avatar.deep.id}</h1>
  )
})

I koden ovan är både memo och useEffect trasiga. memo ska rendera komponenten om props har ändrats, och hoppa över renderingen om de inte har ändrats. Men det kommer att se ut som om avatar aldrig ändras, och därför kommer det aldrig att rendreras om. På samma sätt, om komponenten faktiskt renderar, kommer use effect för alltid att tro att avatar inte ändras, och kommer inte att köra om effekten.

Relaterade artiklar