SetState'in işlevsel sözdiziminin işlevsel bileşenlere tepki vermede kullanımı nedir? [çiftleme]

Dec 13 2020

sahip olan fonksiyonel bileşenlerden bahsediyoruz useState

diyelimki

const [age, setAge] = useState(0)

şimdi güncelleme sırasında öncekini agekullanmam gerektiğini söyleyelimage

React belgeleri , bir işlevi iletebileceğiniz FONKSİYONEL GÜNCELLEMELER adı verilen bir şeyden bahseder ve bunun argümanı, durumun önceki değeri olacaktır, örn.

setState((previousAge) => previousAge + 1)

Sadece yapabildiğimde neden bunu yapmam gerekiyor?

setState(previousAge + 1)

işlevsel kullanmanın faydaları nelerdir setState,

Sınıf tabanlı bileşenlerde işlevsel olarak durum güncellemelerinin gruplanması denen bir şey olduğunu biliyorum , ancak işlevsel bileşen belgelerinde buna benzer bir şey bulamıyorum.

Yanıtlar

2 ehab Dec 14 2020 at 01:38

Aynı değildirler, güncellemeniz eyalette bulunan önceki bir değere bağlıysa, o zaman işlevsel formu kullanmalısınız. Bu durumda işlevsel formu kullanmazsanız, kodunuz bazen kırılır.

Neden ve ne zaman kırılıyor

React fonksiyonel bileşenleri sadece kapanışlardır, kapanışta sahip olduğunuz durum değeri güncelliğini yitirmiş olabilir - bu, kapanış içindeki değerin o bileşen için React durumundaki değerle eşleşmediği anlamına gelir, bu, aşağıdaki durumlar:

1- eşzamansız işlemler ( Bu örnekte yavaş ekle'ye tıklayın ve ardından ekle düğmesine birden çok kez tıklayın, daha sonra yavaş ekle düğmesi tıklandığında durumun kapanmanın içindekine sıfırlandığını göreceksiniz)

const App = () => {
  const [counter, setCounter] = useState(0);

  return (
    <>
      <p>counter {counter} </p>
      <button
        onClick={() => {
          setCounter(counter + 1);
        }}
      >
        immediately add
      </button>
      <button
        onClick={() => {
          setTimeout(() => setCounter(counter + 1), 1000);
        }}
      >
        Add
      </button>
    </>
  );
};

2- Güncelleme işlevini aynı kapanışta birden çok kez çağırdığınızda

const App = () => {
  const [counter, setCounter] = useState(0);

  return (
    <>
      <p>counter {counter} </p>
      <button
        onClick={() => {
          setCounter(counter + 1);
          setCounter(counter + 1);
        }}
      >
        Add twice
      </button>
   
    </>
  );
}
1 HeroWanders Dec 13 2020 at 23:59

Ayarlayıcınızın ne kadar hızlı / sıklıkla arandığına bağlı olarak sorunlar ortaya çıkabilir.

Kapanıştan değeri alarak basit yolu kullanıyorsanız, iki render arasındaki sonraki çağrılar istenen etkiyi yaratmayabilir.

Basit bir örnek:

function App() {
    const [counter, setCounter] = useState(0);
    const incWithClosure = () => {
        setCounter(counter + 1);
    };
    const incWithUpdate = () => {
        setCounter(oldCounter => oldCounter + 1);
    };

    return (<>
        <button onClick={_ => { incWithClosure(); incWithClosure(); }}>
            Increment twice using incWithClosure
        </button>
        <button onClick={_ => { incWithUpdate(); incWithUpdate(); }}>
            Increment twice using incWithUpdate
        </button>
        <p>{counter}</p>
    </>);
}

Her iki düğme de artırma yöntemlerinden birini iki kez çağırır. Ancak şunu gözlemliyoruz:

  • İlk düğme, sayacı yalnızca 1 artıracaktır
  • İkinci düğme, sayacı 2 artıracaktır, bu muhtemelen istenen sonuçtur.

Bu ne zaman olabilir?

  • Açıkçası, eğer incWithClosurebirbiri ardına birden çok kez çağrılırsa
  • Eşzamansız görevler söz konusuysa, bu kolayca gerçekleşebilir (aşağıya bakın)
  • Belki de React'in yapacak çok işi varsa, zamanlama algoritmaları aynı olay işleyicisini kullanarak çok sayıda çok hızlı tıklamayı işlemeye karar verebilir.

Eşzamansız çalışma örneği (bir kaynağın yüklenmesini simüle ederek):

function App() {
  const [counter, setCounter] = useState(0);
  const incWithClosureDelayed = () => {
    setTimeout(() => {
      setCounter(counter + 1);
    }, 1000);
  };
  const incWithUpdateDelayed = () => {
    setTimeout(() => {
      setCounter((oldCounter) => oldCounter + 1);
    }, 1000);
  };

  return (
    <>
      <button onClick={(_) => incWithClosureDelayed()}>
        Increment slowly using incWithClosure
      </button>
      <button onClick={(_) => incWithUpdateDelayed()}>
        Increment slowly using incWithUpdate
      </button>
      <p>{counter}</p>
    </>
  );
}

İlk düğmeye iki kez tıklayın (bir saniye içinde) ve sayacın yalnızca 1 arttığını gözlemleyin. İkinci düğme doğru davranışa sahiptir.

slebetman Dec 13 2020 at 23:26

Eğer yoksa Çünkü olacaktır sizin için eski bir değeri elde noktada bulmak age. Sorun şu ki, bazen önerdiğiniz şey işe yarayacak. Ama bazen olmayacak. Bugün mevcut kodunuzda kırılmayabilir, ancak birkaç hafta önce yazdığınız farklı bir kodda veya şu andaki kodunuzda birkaç ay sonra kırılabilir.

Belirti gerçekten çok tuhaf. Bir jsx bileşeninin içindeki değişkenin değerini {x}sözdizimini kullanarak yazdırabilir ve daha console.log sonra jsx bileşenini oluşturduktan sonra (daha önce değil) kullanarak aynı değişkeni yazdırabilir ve console.logdeğerin eski olduğunu görebilirsiniz - işlemeden console.logsonra gerçekleşen şey bir şekilde daha eski değere sahip olabilir renderdan daha fazla.

Dolayısıyla, durum değişkenlerinin gerçek değeri normal kodda her zaman doğru çalışmayabilir - bunlar yalnızca bir işlemedeki en son değeri döndürmek için tasarlanmıştır. Bu nedenle, bir durum ayarlayıcısındaki geri çağrı mekanizması, bir render dışında normal koddaki bir durum değişkeninin en son değerini almanıza izin vermek için uygulandı.