Reactjs'de setState neden Eşitleme yerine Async?


127

this.setState()Herhangi bir bileşendeki react fonksiyonunun asenkron olduğunu veya çağrıldığı fonksiyonun tamamlanmasından sonra çağrıldığını yeni buldum .

Şimdi bu blogu aradım ve buldum ( setState () Durum Mutasyon İşlemi ReactJS'de Senkronize Olabilir )

Burada setState, durum değişikliğinin nasıl tetiklendiğine bağlı olarak asenkron (yığın boş olduğunda çağrılır) veya senkronize (çağrılır çağrılır) olduğunu buldu.

Şimdi bu iki şeyi sindirmek zor

  1. Blogda setStateişlev bir işlevin içinde çağrılır updateState, ancak updateStateişlevi tetikleyen, çağrılan işlevin bileceği bir şey değildir.
  2. setStateJS tek iş parçacıklı bir dil olduğundan ve bu setState bir WebAPI veya sunucu çağrısı olmadığından, yalnızca JS'nin iş parçacığında yapılması gerektiği için neden eşzamansız yapsınlar? Bunu Re-Rendering'in tüm olay dinleyicilerini ve diğer şeyleri durdurmaması için mi yapıyorlar yoksa başka bir tasarım sorunu mu var?


1
Bugün, iklimin birazını açıklamaya yardımcı olan bir makale yazdım setState: medium.com/@agm1984/…
agm1984

Yanıtlar:


157

Durum değeri güncellendikten sonra bir işlevi çağırabilirsiniz:

this.setState({foo: 'bar'}, () => { 
    // Do something here. 
});

Ayrıca, aynı anda güncellenecek çok sayıda durumunuz varsa, hepsini aynı şekilde gruplandırın setState:

Onun yerine:

this.setState({foo: "one"}, () => {
    this.setState({bar: "two"});
});

Sadece şunu yap:

this.setState({
    foo: "one",
    bar: "two"
});

18
ya thats ok, kullanabileceğimiz bir callBack fonksiyonumuz var ama soru değil dats.
Anup

12
Umarım bu soruya nasıl rastladığına başka birine yardımcı olur.
JoeTidee

2
ya dat yardımcı olabilir
Anup

97

1) setStateeylemler eşzamansızdır ve performans kazanımları için gruplandırılır. Bu, belgelerinde açıklanmıştır setState.

setState () this.state'i hemen değiştirmez, ancak bir bekleyen durum geçişi oluşturur. Bu yöntemi çağırdıktan sonra this.state'e erişmek potansiyel olarak mevcut değeri döndürebilir. SetState'e yapılan çağrıların eşzamanlı olarak çalışacağına dair bir garanti yoktur ve çağrılar performans kazanımları için toplu olarak işlenebilir.


2) JS tek iş parçacıklı bir dil olduğundan ve bu setStatebir WebAPI veya sunucu çağrısı olmadığından neden setState'i zaman uyumsuz yapsınlar ?

Bunun nedeni setState, durumu değiştirmesi ve yeniden oluşturmaya neden olmasıdır. Bu pahalı bir işlem olabilir ve eşzamanlı hale getirmek tarayıcıyı yanıt vermeyebilir.

Böylece setState çağrıları, daha iyi kullanıcı arayüzü deneyimi ve performansı için eşzamansız ve toplu olarak yapılır.


59
Bir setState çağrısı yapıldıktan sonra olayların sıralanmasını sağlamanız gerekiyorsa, bir geri çağrı işlevini iletebilirsiniz. this.setState({ something: true }, () => console.log(this.state))
2016

1
Açıklama için teşekkür ederim @Sachin. Ancak yine de şüphem var, blogun açıkladığı gibi eşzamanlı olabilir mi?
Ajay Gaur

2
Tepki olarak başka bir aptal tasarım kararı. Durum güncellemesini eşzamanlı ve oluşturmayı eşzamansız yapın. İşlemleri toplu olarak yapabilirsiniz, ancak yarış koşullarıyla uğraşmak zorunda kalmadan durum değişkenleri kadar ilkel bir şey ayarlayabilmek istiyorum.
ig-dev

İşlevi zaman uyumsuz veya eşzamanlı yapmak için bir seçeneğin ayarlanmasına neden izin vermiyorsunuz? Bu kullanışlı bir özellik olurdu
Randall Coding

Açıkçası, react ekibinde değilim, ancak bence durum güncellemesini zaman uyumsuz yapmanın bir nedeni, tarayıcıların tek iş parçacıklı olmasıdır. Senkronizasyon işlemleri, kullanıcı arayüzünü tepkisiz hale getirebilir ve UI için iyi bir aday değildir.
Sachin

16

Bu sorunun eski olduğunu biliyorum, ancak ben de dahil olmak üzere birçok reactjs kullanıcısı için uzun süredir çok fazla kafa karışıklığına neden oluyor. Geçenlerde Dan Abramov (tepki ekibinden), neden doğanın doğasına dair harika bir açıklama yazdı.setState eşzamansız :

https://github.com/facebook/react/issues/11527#issuecomment-360199710

setStateasenkron olması amaçlanmıştır ve Dan Abramov'un bağlantılı açıklamasında bunun için gerçekten iyi birkaç neden vardır. Bu, her zaman eşzamansız olacağı anlamına gelmez - esas olarak, eşzamanlı olmasına güvenemeyeceğiniz anlamına gelir . ReactJS, gerçekte ne zaman güncellenmesi ve bileşeninizin yeniden oluşturulması gerektiğine karar vermek için durumu değiştirdiğiniz senaryodaki birçok değişkeni dikkate alır . Bunu göstermenin basit bir örneği, bir kullanıcı eylemine tepki olarak çağırırsanız , muhtemelen hemen güncellenecektir (yine de buna güvenemezsiniz), böylece kullanıcı herhangi bir gecikme hissetmez. ama ararsanstate
setStatestatesetState Bir ajax çağrısı yanıtına veya kullanıcı tarafından tetiklenmeyen başka bir olaya tepki olarak, durum hafif bir gecikmeyle güncellenebilir, çünkü kullanıcı bu gecikmeyi gerçekten hissetmeyecektir ve bekleyerek performansı artıracaktır. birden çok durum güncellemesini bir araya toplayın ve DOM'u daha az kez yeniden oluşturun.


doğru cevap olarak işaretlemediniz. İnsanlar bunun üzerinden nasıl geçileceğini yazıyor. Sorulan sorunun cevabı değil. bu makale iyi görünüyor.
Anup

@Anup Cevap, "eşzamansız" veya "eşzamanlı" dan biraz daha karmaşık. Her zaman "eşzamansız" olarak ele alınmalıdır, ancak bazı durumlarda "eşzamanlı" olarak davranabilir. Umarım sana biraz ışık tutmuşumdur.
gillyb

8

İyi makale burada https://github.com/vasanthk/react-bits/blob/master/patterns/27.passing-function-to-setState.md

// assuming this.state.count === 0
this.setState({count: this.state.count + 1});
this.setState({count: this.state.count + 1});
this.setState({count: this.state.count + 1});
// this.state.count === 1, not 3

Solution
this.setState((prevState, props) => ({
  count: prevState.count + props.increment
}));

veya geri aramayı geç this.setState ({.....},callback)

https://medium.com/javascript-scene/setstate-gate-abc10a9b2d82 https://medium.freecodecamp.org/functional-setstate-is-the-future-of-react-374f30401b6b


7

Senkronizasyon çağrısı yapmak için aşağıdaki sarmayı kullanabilirsiniz

this.setState((state =>{
  return{
    something
  }
})


hafife alınmamış cevap
James Cat

1

Bir bileşende bir sayacı artırdığınızı hayal edin:

  class SomeComponent extends Component{

    state = {
      updatedByDiv: '',
      updatedByBtn: '',
      counter: 0
    }

    divCountHandler = () => {
      this.setState({
        updatedByDiv: 'Div',
        counter: this.state.counter + 1
      });
      console.log('divCountHandler executed');
    }

    btnCountHandler = () => {
      this.setState({
        updatedByBtn: 'Button',
        counter: this.state.counter + 1
      });
      console.log('btnCountHandler executed');
    }
    ...
    ...
    render(){
      return (
        ...
        // a parent div
        <div onClick={this.divCountHandler}>
          // a child button
          <button onClick={this.btnCountHandler}>Increment Count</button>
        </div>
        ...
      )
    }
  }

Hem üst hem de alt bileşenlere eklenmiş bir sayım işleyicisi vardır. Bu bilinçli olarak yapılır, böylece setState () 'i aynı tıklama olayı köpürme bağlamında, ancak 2 farklı işleyiciden iki kez çalıştırabiliriz.

Tahmin edebileceğimiz gibi, olay köpürme aşaması sırasında hedeften en dıştaki konteynere doğru kabarcıklar oluşturduğundan, düğme üzerindeki tek bir tıklama olayı artık bu iki işleyiciyi de tetikleyecektir.

Bu nedenle, önce btnCountHandler () çalıştırılır, sayımı 1'e yükseltmesi beklenir ve ardından divCountHandler () çalıştırılır ve sayımı 2'ye yükseltmesi beklenir.

Ancak, React Developer araçlarında inceleyebileceğiniz gibi sayı yalnızca 1'e yükselir.

Bu tepki verdiğini kanıtlıyor

  • tüm setState çağrılarını sıralar

  • bağlamdaki son yöntemi çalıştırdıktan sonra bu kuyruğa geri döner (bu durumda divCountHandler)

  • Birden fazla setState çağrısında meydana gelen tüm nesne mutasyonlarını aynı bağlamda (tek bir olay fazındaki tüm yöntem çağrıları örneğin aynı bağlamdır) tek bir nesne mutasyon sözdiziminde birleştirir (birleştirme mantıklıdır çünkü bu nedenle durum özelliklerini bağımsız olarak güncelleyebiliriz setState () ilk etapta)

  • ve birden çok setState () çağrısı nedeniyle yeniden oluşturmayı önlemek için tek bir setState () öğesine aktarır (bu, yığınlamanın çok ilkel bir açıklamasıdır).

React tarafından çalıştırılan sonuç kodu:

this.setState({
  updatedByDiv: 'Div',
  updatedByBtn: 'Button',
  counter: this.state.counter + 1
})

Bu davranışı durdurmak için, nesneleri argüman olarak setState yöntemine iletmek yerine geri çağrılar iletilir.

    divCountHandler = () => {
          this.setState((prevState, props) => {
            return {
              updatedByDiv: 'Div',
              counter: prevState.counter + 1
            };
          });
          console.log('divCountHandler executed');
        }

    btnCountHandler = () => {
          this.setState((prevState, props) => {
            return {
              updatedByBtn: 'Button',
              counter: prevState.counter + 1
            };
          });
      console.log('btnCountHandler executed');
    }

Son yöntem yürütmeyi bitirdikten sonra ve react setState kuyruğunu işlemek için geri döndüğünde, sıradaki her setState için geri çağrıyı çağırır ve önceki bileşen durumuna geçer.

Bu şekilde tepki, kuyruktaki son geri aramanın önceki tüm muadillerinin el koyduğu durumu güncellemesini sağlar.


0

Evet, setState () eşzamansızdır.

Bağlantıdan: https://reactjs.org/docs/react-component.html#setstate

  • React, durum değişikliklerinin hemen uygulanacağını garanti etmez.
  • setState () bileşeni her zaman hemen güncellemez.
  • SetState () 'i, bileşeni güncellemek için anında bir komut olarak değil, bir istek olarak düşünün.

Çünkü
bağlantıdan düşünüyorlar : https://github.com/facebook/react/issues/11527#issuecomment-360199710

... setState () eşzamanlı olarak yeniden oluşturmanın çoğu durumda verimsiz olacağını kabul ediyoruz

Eşzamansız setState (), yeni başlayanlar ve hatta maalesef deneyimli olanlar için hayatı çok zorlaştırır:
- beklenmeyen oluşturma sorunları: gecikmeli oluşturma veya oluşturma yok (program mantığına göre)
- parametreleri iletmek çok önemlidir
diğer sorunların yanı sıra çok önemlidir.

Aşağıdaki örnek yardımcı oldu:

// call doMyTask1 - here we set state
// then after state is updated...
//     call to doMyTask2 to proceed further in program

constructor(props) {
    // ..

    // This binding is necessary to make `this` work in the callback
    this.doMyTask1 = this.doMyTask1.bind(this);
    this.doMyTask2 = this.doMyTask2.bind(this);
}

function doMyTask1(myparam1) {
    // ..

    this.setState(
        {
            mystate1: 'myvalue1',
            mystate2: 'myvalue2'
            // ...
        },    
        () => {
            this.doMyTask2(myparam1); 
        }
    );
}

function doMyTask2(myparam2) {
    // ..
}

Umarım yardımcı olur.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.