ReactJS - “setState” çağrıldığında oluşturma işlemi çağrılıyor mu?


503

React tüm bileşenleri ve alt bileşenleri her seferinde yeniden oluşturur mu? setState çağrıldığında mu?

Öyleyse neden? Fikrin, React'in sadece gerektiği kadar az bir hale getirildiğini düşündüm - devlet değiştiğinde.

Aşağıdaki basit örnekte, onClick işleyicisi her zaman stateaynı değere ayarlandığından, sonraki tıklatmalarda durumun değişmemesine rağmen, metin tıklatıldığında her iki sınıf da yeniden oluşturulur :

this.setState({'test':'me'});

Oluşturma işlemlerinin yalnızca stateveriler değişmiş olsaydı gerçekleşmesini beklerdim.

JS Fiddle ve gömülü snippet olarak örneğin kodu :

var TimeInChild = React.createClass({
    render: function() {
        var t = new Date().getTime();

        return (
            <p>Time in child:{t}</p>
        );
    }
});

var Main = React.createClass({
    onTest: function() {
        this.setState({'test':'me'});
    },

    render: function() {
        var currentTime = new Date().getTime();

        return (
            <div onClick={this.onTest}>
            <p>Time in main:{currentTime}</p>
            <p>Click me to update time</p>
            <TimeInChild/>
            </div>
        );
    }
});

ReactDOM.render(<Main/>, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react-dom.min.js"></script>

[1]: http://jsfiddle.net/fp2tncmb/2/

Aynı sorunu yaşadım, kesin çözümü bilmiyorum. Ama istenmeyen kodları her zamanki gibi çalışmaya başladığı bileşenden temizledim.
Jaison

Örneğinizde - öğenizin nasıl tasarlandığı yalnızca benzersiz bir duruma bağlı olmadığından - setState()kukla verilerle bile çağrıldığında , öğenin farklı bir şekilde görüntülenmesine neden olduğundan, evet diyebilirim. Kesinlikle bir şey değiştiğinde nesnenizi yeniden oluşturmaya çalışmalıdır, aksi takdirde demo - amaçlanan davranış olduğunu varsayarak - işe yaramaz!
Tadhg McDonald-Jensen

Haklısın @ TadhgMcDonald-Jensen - ama benim anlayışımdan, React bunu ilk kez işleyecekti (devlet hiçbir şeyden ilk kez bir şeye değiştiği için), bir daha asla render etmek zorunda kalmayacaktı. Tabii ki yanılmışım - React'ın kendi shouldComponentUpdateyönteminizi yazmanızı gerektirdiği gibi , bunun basit bir versiyonunun zaten React'in içine dahil edilmesi gerektiğini varsaydım. Reaksiyona dahil edilen varsayılan sürüm basitçe geri döner true- bu da bileşeni her seferinde yeniden oluşturmaya zorlar.
Brad Parks

Evet, ancak yalnızca sanal DOM'da yeniden oluşturulması gerekir, ancak bileşen farklı şekilde işlenirse gerçek DOM'u değiştirir. Sanal DOM'daki güncellemeler genellikle ihmal edilebilir (en azından gerçek ekrandaki şeyleri değiştirmeye kıyasla), bu yüzden her güncellemeye ihtiyaç duyduğunda render'i çağırmak ve hiçbir değişikliğin gerçekleşmediğini varsaymaktan çok daha pahalı ve daha güvenli olmadığını görmek.
Tadhg McDonald-Jensen

Yanıtlar:


570

React, setState her çağrıldığında tüm bileşenleri ve alt bileşenleri yeniden oluşturur mu?

Varsayılan olarak - evet.

Bir boolean shouldComponentUpdate (nextProps nesnesi, nextState nesnesi) yöntemi vardır, her bileşen bu yönteme sahiptir ve "bileşen güncellemesi (run rendering function)?" Her zaman değiştirmek durumunu ya da yeni geçen sahne ebeveyn bileşeninden.

ShouldComponentUpdate uygulamasına kendi uygulamanızı yazabilirsiniz için yönteminin , ancak varsayılan uygulama her zaman true döndürür;

Resmi dokümanlardan alıntı http://facebook.github.io/react/docs/component-specs.html#updating-shouldcomponentupdate

Varsayılan olarak, durum mutasyona uğradığında ince hataları önlemek için shouldComponentUpdate her zaman true değerini döndürür, ancak durumu her zaman değişmez olarak ele almaya ve render () öğesindeki sahne ve durumlardan salt okunur olmaya dikkat ederseniz shouldComponentUpdate ile geçersiz kılabilirsiniz. eski destekleri ve durumu değiştirmeleriyle karşılaştıran bir uygulama.

Sorunuzun sonraki kısmı:

Öyleyse neden? Fikrin, React'in sadece gerektiği kadar - devlet değiştiğinde - render edildiğini düşündüm.

"Render" diyebileceğimiz şeyin iki adımı vardır:

  1. Sanal DOM oluşturuyor : render yöntemi çağrıldığında bileşenin yeni bir sanal dom yapısı döndürülür . Daha önce de belirttiğim gibi, setState () öğesini çağırdığınızda bu render yöntemi her zaman çağrılır , çünkü shouldComponentUpdate her zaman varsayılan olarak true değerini döndürür. Dolayısıyla, varsayılan olarak, burada React'te bir optimizasyon yoktur.

  2. Yerel DOM oluşturuyor: React, tarayıcınızdaki gerçek DOM düğümlerini yalnızca Sanal DOM'da değiştirildiyse ve gerektiği kadar az değiştirirse değiştirir - bu, gerçek DOM mutasyonunu optimize eden ve React'i hızlı hale getiren harika React'in özelliğidir.


47
Harika bir açıklama! Ve React'i bu durumda gerçekten parlak yapan tek şey , sanal DOM değiştirilmediği sürece gerçek DOM'yi değiştirmemesidir. Dolayısıyla, oluşturma işlevim aynı şeyi arka arkaya 2 kez döndürürse, gerçek DOM hiç değişmez ... Teşekkürler!
Brad Parks

1
Bence @tungd haklı - cevabını aşağıya bakınız. Aynı zamanda bileşenler arasında bir ebeveyn-çocuk ilişkisi söz konusudur. Örneğin, TimeInChild bir Main kardeşiyse , render () gereksiz yere çağrılmaz.
gvlax

2
Durumunuz büyük bir bileşen ağacı (~ toplam 100) olarak görüntülenen nispeten büyük bir javascript nesnesi (~ toplam özellikleri) içeriyorsa ... oluşturma işlevlerinin sanal dom'u oluşturmasına izin vermeniz gerekiyorsa veya durum, yeni durumu eski ile manuel olarak karşılaştırın ve sadece setStatebir fark olduğunu fark ederseniz arayın ? Eğer öyleyse, bu en iyi nasıl yapılır - json dizelerini karşılaştırın, nesne karmaları oluşturun ve karşılaştırın, ...?
Vincent Sels

1
@Petr, ancak tepki sanal dom'u yeniden yapılandırsa da, eski sanal dom yeni sanal dom ile aynıysa, tarayıcı domuna dokunulmaz, değil mi?
Jaskey

3
Ayrıca, React.PureComponent'i ( reaktjs.org/docs/react-api.html#reactpurecomponent ) kullanmaya bakın . Yalnızca bileşenin durumu veya sahne donanımı gerçekten değiştiyse güncellenir (yeniden işler). Ancak, karşılaştırmanın sığ olduğuna dikkat edin.
debater

105

Hayır, React durum değiştiğinde her şeyi yapmaz.

  • Bir bileşen kirlendiğinde (durumu değiştiğinde), bu bileşen ve alt öğeleri yeniden oluşturulur. Bu, bir dereceye kadar, mümkün olduğunca az yeniden canlandırmaktır. Oluşturmanın çağrılmadığı tek zaman, bazı dalların başka bir köke taşındığı zamandır; burada teorik olarak hiçbir şeyi yeniden oluşturmamız gerekmez. Örneğinizde, TimeInChildöğesinin bir alt bileşenidir Main, bu nedenle Maindeğişikliklerin durumu da yeniden oluşturulur .

  • React durum verilerini karşılaştırmaz. Zaman setStateadlandırılan, kirli gibi işaretleri bileşen (demek oluyor yeniden işlenen bulunmasına ihtiyaç vardır). Dikkat edilmesi gereken önemli nokta, renderbileşenin yöntemi çağrılsa da, gerçek DOM yalnızca çıktının geçerli DOM ağacından farklı olması durumunda güncellenir (diğer bir deyişle Sanal DOM ağacı ve belgenin DOM ağacı arasında farklılık gösterir). Örneğinizde, stateveriler değişmese de, son değişiklik zamanı değişti ve Sanal DOM'u belgenin DOM'sinden farklı kıldı, bu nedenle HTML neden güncellendi.


Evet, doğru cevap bu. Bir deneme olarak son satırı React.renderComponent (<div> <Main /> <TimeInChild /> </div>, document.body) olarak değiştirin ; ve kaldırma <TimeInChild /> gövdesinden render () arasında ana bileşen. Render () ait TimeInChild bunun bir alt olmadığı için varsayılan olarak adlandırılan olmayacaktır Main artık.
gvlax

Teşekkürler, bunun gibi şeyler biraz zor, bu yüzden React yazarları render()yöntemin "saf" - dış durumdan bağımsız olmasını önerdi.
tungd

3
@tungd, bu ne anlama geliyor some branch is moved to another root? Ne diyorsun sen branch? Ne diyorsun sen root?
Green

2
Gerçekten doğru olarak işaretlenmiş cevabı tercih ederim. Yerli, 'gerçek', 'taraftaki' render 'yorumunu anlıyorum ... ama buna tepki-yerel tarafından bakarsanız, onun yeniden yarattığını söylemelisiniz. Neyse ki gerçekten neyin değiştiğini belirlemek ve sadece bunları güncellemek için yeterince akıllı. Bu cevap yeni kullanıcılar için kafa karıştırıcı olabilir, önce hayır diyorsunuz ve sonra işlerin işlendiğini açıklıyorsunuz ...
WiRa

1
@tungd u Green'in sorusunu açıklayabilirwhat does it mean some branch is moved to another root? What do you call branch? What do you call root?
madhu131313

7

Buradaki diğer cevapların çoğunda belirtilmesine rağmen, bileşen şunlardan birini yapmalıdır:

  • uygulamak shouldComponentUpdateyalnızca eyalet veya özellikler değişikliği işlemek için

  • halihazırda sığ karşılaştırmalar için dahili olarak bir yöntem uygulayan bir PureComponent öğesini genişletmeye geçin shouldComponentUpdate.

Aşağıda shouldComponentUpdate, yalnızca bu basit kullanım durumu ve gösterim amacıyla çalışan bir örnek verilmiştir . Bu kullanıldığında, bileşen artık her tıklamada kendini yeniden oluşturmaz ve ilk görüntülendiğinde ve bir kez tıklandıktan sonra oluşturulur.

var TimeInChild = React.createClass({
    render: function() {
        var t = new Date().getTime();

        return (
            <p>Time in child:{t}</p>
        );
    }
});

var Main = React.createClass({
    onTest: function() {
        this.setState({'test':'me'});
    },

    shouldComponentUpdate: function(nextProps, nextState) {
      if (this.state == null)
        return true;
  
      if (this.state.test == nextState.test)
        return false;
        
      return true;
  },

    render: function() {
        var currentTime = new Date().getTime();

        return (
            <div onClick={this.onTest}>
            <p>Time in main:{currentTime}</p>
            <p>Click me to update time</p>
            <TimeInChild/>
            </div>
        );
    }
});

ReactDOM.render(<Main/>, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react-dom.min.js"></script>


6

Evet. SetState öğesini her çağırdığımızda bunun yerine "shouldComponentUpdate" yanlış döndürdüğünde render () yöntemini çağırır.


7
Lütfen daha ayrıntılı olun
Karthick Ramesh

3

"Kayıp güncelleme" nin bir başka nedeni şu olabilir:

  • Eğer statik getDerivedStateFromProps sonra tanımlanır resmi belgelere göre her güncelleme işleminde yeniden edilir https://reactjs.org/docs/react-component.html#updating .
  • dolayısıyla bu durum değeri başlangıçtaki desteklerden geliyorsa her güncellemenin üzerine yazılır.

Sorun buysa, U güncelleme sırasında durumun ayarlanmasını önleyebilir, durum parametresi değerini böyle kontrol etmelisiniz

static getDerivedStateFromProps(props: TimeCorrectionProps, state: TimeCorrectionState): TimeCorrectionState {
   return state ? state : {disable: false, timeCorrection: props.timeCorrection};
}

Başka bir çözüm, duruma bir ilklendirilmiş özellik eklemek ve bunu ilk kez ayarlamaktır (durum boş olmayan değere başlatılırsa).


0

Tüm Bileşenler Değil.

stateBileşen görünüyor bütün APP devletin şelale kaynağını gibi.

Böylece değişiklik setState'in çağırdığı yerden olur. O zaman ağacı rendersoradan çağrılır. Saf bileşen kullandıysanız, renderatlanacak.

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.