Redux bağlantılı bir bileşen ne zaman yeniden oluşturulacağını nasıl bilir?


94

Muhtemelen çok bariz bir şeyi kaçırıyorum ve kendimi temizlemek istiyorum.

İşte benim anlayışım.
Saf bir tepki bileşeninde states& var props. Güncellenmesi stateile setStatetüm bileşeni yeniden oluşturur. propsçoğunlukla salt okunurdur ve bunları güncellemek bir anlam ifade etmez.

Bir store.subscribe(render)yeniden satış mağazasına abone olan bir tepki bileşeninde , bunun gibi bir şey aracılığıyla , mağaza her güncellendiğinde açıkça yeniden oluşturulur.

react-redux , connect()durum ağacının bir kısmını (yani bileşenin ilgisini çeker) ve actionCreators'ı propsbileşenle ilgili olarak, genellikle aşağıdaki gibi bir şey aracılığıyla enjekte eden bir yardımcıya sahiptir.

const TodoListComponent = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)

Ancak, a'nın yeniden düzenleme durum ağacı değişikliğine (yeniden oluşturma) tepki vermesi setStateiçin gerekli olduğu anlayışıyla , bileşen dosyasında TodoListComponentherhangi bir stateveya setStateilgili kod bulamıyorum TodoList. Şöyle bir şey okur:

const TodoList = ({ todos, onTodoClick }) => (
  <ul>
    {todos.map(todo =>
      <Todo
        key={todo.id}
        {...todo}
        onClick={() => onTodoClick(todo.id)}
      />
    )}
  </ul>
)

Biri bana neyi kaçırdığım konusunda doğru yönü gösterebilir mi?

Not: Redux paketi ile birlikte verilen yapılacaklar listesi örneğini takip ediyorum .

Yanıtlar:


116

connectİşlev saklamak için abone olan bir sargı bileşenini oluşturur. Bir eylem gönderildiğinde, sarmalayıcı bileşeninin geri çağrısı bildirilir. Daha sonra, mapStateişlevinizi çalıştırır ve bu zamandaki sonuç nesnesini son seferdeki sonuç nesnesi ile yüzeysel olarak karşılaştırır (bu nedenle , aynı değerde bir yeniden düzenleme deposu alanını yeniden yazarsanız, yeniden oluşturmayı tetiklemeyecektir). Sonuçlar farklıysa, sonuçları sahne olarak "gerçek" bileşeninize aktarır.

Dan Abramov , optimizasyon çalışmalarının hiçbirini göstermese de temel fikri gösteren harika bir basitleştirilmiş connectat ( connect.js ) sürümü yazdı . Ayrıca, bazı ilgili fikirleri tartışan Redux performansı ile ilgili birkaç makaleye bağlantılar da var .

Güncelleme

React-Redux v6.0.0 , bağlı bileşenlerin verilerini mağazadan nasıl alacakları konusunda bazı önemli dahili değişiklikler yaptı.

Bunun bir parçası olarak, connectAPI'nin ve iç bileşenlerinin nasıl çalıştığını ve zaman içinde nasıl değiştiklerini açıklayan bir yazı yazdım :

Deyimsel Redux: React-Redux'un Tarihçesi ve Uygulaması


Teşekkürler! Geçen gün bana HN - news.ycombinator.com/item?id=12307621 ile faydalı bağlantılarla yardım eden aynı kişi misiniz ? Tanıştığımıza memnun oldum :)
Joe Lewis

4
Evet, benim o :) ben harcamak yolu çevrimiçi Redux üzerinde tartışmalar arayan çok fazla zaman - SO Reddit, HN, Orta ve diğer çeşitli yerlerde. Yardımcı olduğuma sevindim! (Ayrıca Bilginize, Discord'daki Reactiflux sohbet kanallarını şiddetle tavsiye ediyorum. Orada takılan ve soruları yanıtlayan birçok kişi var. Genellikle ABD EST akşamları çevrimiçi oluyorum. Davet bağlantısı reactiflux.com'da .)
markerikson

Bunun soruyu cevapladığını varsayarsak, cevabı kabul eder misiniz? :)
markerikson

Nesnelerin kendilerini mi yoksa nesnelerden önceki / sonraki özelliklerini mi karşılaştırıyor? İkincisi ise, sadece ilk seviyeyi kontrol ediyor mu, "sığ" derken kastettiğin bu mu?
Andy

Evet, bir "yüzeysel eşitlik onay" anlamına gelir, her nesnenin ilk seviye alanlarını karşılaştırmak için: prev.a === current.a && prev.b === current.b && ...... Bu, herhangi bir veri değişikliğinin yeni referanslarla sonuçlanacağını varsayar, bu da doğrudan mutasyon yerine değişmez veri güncellemelerinin gerekli olduğu anlamına gelir.
markerikson

14

Cevabım biraz sol alanın dışında. Beni bu gönderiye götüren bir soruna ışık tutuyor. Benim durumumda, yeni sahne almasına rağmen uygulama yeniden oluşturulmuyor gibi görünüyordu.
React geliştiricileri, sıkça sorulan bu soruya, (mağaza) mutasyona uğramışsa, zamanın% 99'unda tepkinin yeniden oluşturulmayacağına dair bir yanıt aldı. Yine de diğer% 1 hakkında hiçbir şey yok. Burada mutasyon söz konusu değildi.


TLDR;

componentWillReceivePropsyeni ile nasıl statesenkronize tutulabileceğidir props.

Kenar Olgu: Bir kez stategüncellemeler, daha sonra uygulama yok yeniden işlemek!


Uygulamanız yalnızca stateöğelerini görüntülemek için kullanıyorsa propsgüncellenebilir, ancak güncellenmez state, bu nedenle yeniden oluşturulamaz.

Ben statebağımlı olduğunu propsredux alınan store. İhtiyaç duyduğum veriler henüz mağazada değildi, bu yüzden componentDidMountuygun olduğu gibi buradan aldım . İndirgeyicim mağazamı güncellediğinde malzemeleri geri aldım, çünkü bileşenim mapStateToProps aracılığıyla bağlı. Ancak sayfa görüntülenmedi ve durum hala boş dizelerle doluydu.

Buna bir örnek, bir kullanıcının kayıtlı bir url'den bir "gönderiyi düzenle" sayfası yüklediğini varsayabilir. URL'sine erişiminiz var postId, ancak bilgi storehenüz içinde değil , bu yüzden onu alın. Sayfanızdaki öğeler denetlenen bileşenlerdir - bu nedenle görüntülediğiniz tüm veriler içeride olur state.

Redux kullanılarak veriler getirildi, mağaza güncellendi ve bileşen connectdüzenlendi, ancak uygulama değişiklikleri yansıtmadı. Daha yakından bakıldığında propsalındı, ancak uygulama güncellenmedi. stategüncellenmedi.

Eh, propsgüncellenecek ve yayılacak, ancak stateolmayacak. Özellikle stategüncellemeyi söylemeniz gerekir .

Bunu yapamazsınız render()ve componentDidMountdöngülerini zaten bitirdiniz.

componentWillReceivePropsstatedeğişen bir propdeğere bağlı olan özellikleri güncellediğiniz yerdir .

Örnek Kullanım:

componentWillReceiveProps(nextProps){
  if (this.props.post.category !== nextProps.post.category){
    this.setState({
      title: nextProps.post.title,
      body: nextProps.post.body,
      category: nextProps.post.category,
    })
  }      
}

Düzinelerce başka gönderi, blog ve deponun bahsetmediği çözüm konusunda beni aydınlatan bu makaleye bir haykırmak zorundayım. Açıkça anlaşılamayan bu soruna cevap bulmakta güçlük çeken herhangi biri, İşte:

ReactJs bileşen yaşam döngüsü yöntemleri - Ayrıntılı bir inceleme

componentWillReceivePropsgüncellemelerle statesenkronize tutmak için güncelleme yapacağınız yerdir props.

Bir kez stategüncellemeler, daha sonra bağlı alanların state do yeniden işlemek!


3
Gönderen React 16.3itibaren, sen gerektiğini kullanmak getDerivedStateFromPropsyerine componentWillReceiveProps. Ama aslında, hatta tüm yapmamam gerektiğini dile şekilde burada
kyw

o çalışmıyor, durum değiştiğinde, componentWillReceiveProps o kadar çok durumda çalışacak ki deniyorum, bu işe yaramıyor. Özellikle, çok seviyeli iç içe geçmiş veya karmaşık proplar, bu nedenle bir ID ile bileşen atamalı ve bunun için değişikliği tetiklemem ve yeni verileri yeniden oluşturmak için durumu güncellemem gerekiyor
May'Habit

0

Bu cevap, Brian Vaughn'un Muhtemelen Türetilmiş Duruma İhtiyacınız Yok başlıklı makalesinin bir özetidir (7 Haziran 2018).

Nesnelerden durum türetmek, tüm biçimleriyle bir anti-modeldir. Eski componentWillReceivePropsve yeniyi kullanmak dahil getDerivedStateFromProps.

Durumu proplardan türetmek yerine, aşağıdaki çözümleri düşünün.

En iyi iki uygulama önerisi

Öneri 1. Tam kontrollü bileşen
function EmailInput(props) {
  return <input onChange={props.onChange} value={props.email} />;
}
Öneri 2. Anahtarlı, tamamen kontrolsüz bileşen
// parent class
class EmailInput extends Component {
  state = { email: this.props.defaultEmail };

  handleChange = event => {
    this.setState({ email: event.target.value });
  };

  render() {
    return <input onChange={this.handleChange} value={this.state.email} />;
  }
}

// child instance
<EmailInput
  defaultEmail={this.props.user.email}
  key={this.props.user.id}
/>

Her ne sebeple olursa olsun, öneriler sizin durumunuz için işe yaramazsa iki alternatif.

Alternatif 1: Kontrolsüz bileşeni bir ID prop ile sıfırlayın
class EmailInput extends Component {
  state = {
    email: this.props.defaultEmail,
    prevPropsUserID: this.props.userID
  };

  static getDerivedStateFromProps(props, state) {
    // Any time the current user changes,
    // Reset any parts of state that are tied to that user.
    // In this simple example, that's just the email.
    if (props.userID !== state.prevPropsUserID) {
      return {
        prevPropsUserID: props.userID,
        email: props.defaultEmail
      };
    }
    return null;
  }

  // ...
}
Alternatif 2: Bir örnek yöntemiyle kontrolsüz bileşeni sıfırlayın
class EmailInput extends Component {
  state = {
    email: this.props.defaultEmail
  };

  resetEmailForNewUser(newEmail) {
    this.setState({ email: newEmail });
  }

  // ...
}

-2

redux'un yaptığı tek şey bildiğim gibi, mağazanın durumu değiştiğinde componentWillRecieveProps çağırıyor eğer bileşeniniz mutasyona uğramış duruma bağımlıysa ve sonra bileşeninizi güncellemeye zorlamalısınız.

1-mağaza Durum değişikliği-2-çağrısı (componentWillRecieveProps (() => {3-bileşenli durum değişikliği}))

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.