Bileşenlerimizin amacına / boyutuna / desteklerine / davranışına göre bu üçü arasında nasıl seçim yaparsınız?
Özel bir yöntemden React.PureComponentveya bu yöntemle genişletmenin performans sonuçları vardır. Vatansız fonksiyonel bileşenleri kullanmak "mimari" bir seçimdir ve kutudan çıktığı haliyle performans avantajı yoktur (henüz).React.ComponentshouldComponentUpdate
Kolayca yeniden kullanılması gereken basit, yalnızca sunumsal bileşenler için durum bilgisi olmayan fonksiyonel bileşenleri tercih edin. Bu şekilde, gerçek uygulama mantığından ayrıldıklarından, test edilmeleri son derece kolay olduklarından ve beklenmedik yan etkilere sahip olmadıklarından emin olabilirsiniz. İstisna, bir nedenden ötürü çok fazla şeye sahipseniz veya gerçekten oluşturma yöntemlerini optimize etmeniz gerekiyorsa ( shouldComponentUpdatevatansız bir fonksiyonel bileşen için tanımlayamadığınız için).
PureComponentÇıktınızın basit sahne / duruma ("basit" anlamına gelir) genişletin (PureComponent sığ bir karşılaştırma gerçekleştirdiğinden iç içe veri yapıları yoktur) VE bazı performans geliştirmelerine ihtiyacınız var / alabilirsiniz.
Bir sonraki / mevcut sahne ve durum arasında özel karşılaştırma mantığı gerçekleştirerek performans kazançlarına ihtiyacınız varsa kendiniz genişletin Componentve uygulayın shouldComponentUpdate. Örneğin, lodash # isEqual kullanarak hızlı bir şekilde derin bir karşılaştırma yapabilirsiniz:
class MyComponent extends Component {
shouldComponentUpdate (nextProps, nextState) {
return !_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState);
}
}
Ayrıca, kendiniz uygulamak shouldComponentUpdateveya genişletmek PureComponentoptimizasyonlardır ve her zamanki gibi bunu yalnızca performans sorunlarınız varsa ( erken optimizasyonlardan kaçının ) araştırmaya başlamalısınız . Genel bir kural olarak, bu optimizasyonları her zaman uygulama çalışır durumda ve özelliklerin çoğu zaten uygulandıktan sonra yapmaya çalışırım. Gerçekte yol aldıklarında performans sorunlarına odaklanmak çok daha kolay.
Daha fazla detay
Fonksiyonel vatansız bileşenler:
Bunlar sadece bir fonksiyon kullanılarak tanımlanır. Durum bilgisi olmayan bir bileşen için dahili bir durum olmadığından, çıktı (işlenenler) yalnızca bu işleve giriş olarak verilen desteklere bağlıdır.
Artıları:
React'ta bir bileşeni tanımlamanın mümkün olan en basit yolu. Herhangi bir durumu yönetmeniz gerekmiyorsa, neden sınıflar ve mirasla uğraşasınız ki? Bir işlev ve sınıf arasındaki ana farklardan biri, işlevle çıktının yalnızca girdiye bağlı olduğundan emin olmanızdır (önceki yürütmelerin herhangi bir geçmişine değil).
İdeal olarak uygulamanızda olabildiğince çok vatansız bileşenlere sahip olmayı hedeflemelisiniz, çünkü bu normalde mantığınızı görünüm katmanının dışına taşıdığınız ve redux gibi bir şeye taşıdığınız anlamına gelir; (test edilmesi çok daha kolay, daha fazla kullanılabilir vb.).
Eksileri:
Yaşam döngüsü yöntemi yok. Sizin componentDidMountve diğer arkadaşlarınızı tanımlamanın bir yolu yok . Normalde bunu, tüm çocukları vatansız olanlara dönüştürebilmeniz için hiyerarşide daha büyük bir üst bileşen içinde yaparsınız.
Yeniden oluşturma gerektiğinde manuel olarak kontrol etmenin bir yolu yoktur, çünkü tanımlayamazsınız shouldComponentUpdate. Yeniden oluşturma işlemi, bileşen her yeni sahne aldığında gerçekleşir (sığ karşılaştırmanın yolu yoktur). Gelecekte, React vatansız bileşenleri otomatik olarak optimize edebilir, çünkü şimdi kullanabileceğiniz bazı kütüphaneler var. Vatansız bileşenler sadece işlevler olduğundan, temelde "işlev belleği" nin klasik problemidir.
Referanslar desteklenmiyor: https://github.com/facebook/react/issues/4936
PureComponent sınıfını genişleten bir bileşen VS Bileşen sınıfını genişleten normal bir bileşen:
Bir için kullanılan tepki PureRenderMixinkullanmakta tanımlanan bir sınıfa eklemek olabilir React.createClasssözdizimi. Mixin, bir shouldComponentUpdateşeylerin değişip değişmediğini kontrol etmek için bir sonraki sahne ile bir sonraki durum arasında sığ bir karşılaştırma yapmayı tanımlar . Hiçbir şey değişmezse, yeniden oluşturma gerçekleştirmeye gerek yoktur.
ES6 sözdizimini kullanmak istiyorsanız, mixins kullanamazsınız. Kolaylık sağlamak için React PureComponentkullanmak yerine kalıtım yoluyla alabileceğiniz bir sınıf tanıttı Component. PureComponentsadece shouldComponentUpdateaynı şekilde uygular PureRendererMixin. Çoğunlukla kullanışlı bir şeydir, bu yüzden bunu kendiniz uygulamak zorunda kalmazsınız, çünkü mevcut / sonraki durum ve sahne arasında sığ bir karşılaştırma muhtemelen bazı hızlı performans kazançları sağlayabilecek en yaygın senaryodur.
Misal:
class UserAvatar extends Component {
render() {
return <div><img src={this.props.imageUrl} /> {{ this.props.username }} </div>
}
}
Gördüğünüz gibi çıktı props.imageUrlve props.username. Bir üst bileşende <UserAvatar username="fabio" imageUrl="http://foo.com/fabio.jpg" />aynı sahne ile oluşturursanız render, çıktı tam olarak aynı olsa bile React her seferinde çağrı yapacaktır. React'in dom farkını uyguladığını unutmayın, bu nedenle DOM aslında güncellenmez. Yine de, dom farkını gerçekleştirmek pahalı olabilir, bu nedenle bu senaryoda bir atık olacaktır.
Eğer UserAvatarbileşen uzanır PureComponentyerine, karşılaştırma sığ yapılır. Ve props ve nextProps aynı olduğundan render, hiç çağrılmaz.
React'te "pure" tanımı ile ilgili notlar:
Genel olarak, "saf işlev", aynı girdi göz önüne alındığında her zaman aynı sonucu değerlendiren bir işlevdir. Çıktı (React için, renderyöntem tarafından döndürülen budur ) herhangi bir geçmişe / duruma bağlı değildir ve herhangi bir yan etkisi yoktur (işlevin dışındaki "dünya" yı değiştiren işlemler).
React'te, vatansız bileşenler, asla çağırmayan this.setStateve kullanmayan bir bileşeni "vatansız" olarak adlandırırsanız, yukarıdaki tanıma göre mutlaka saf bileşenler değildir this.state.
Aslında, a'da, PureComponentyaşam döngüsü yöntemleri sırasında hala yan etkiler yapabilirsiniz. Örneğin, içine bir ajax isteği gönderebilir componentDidMountveya içindeki bir div'in yüksekliğini dinamik olarak ayarlamak için bazı DOM hesaplamaları yapabilirsiniz render.
"Aptal bileşenler" tanımının daha "pratik" bir anlamı vardır (en azından benim anlayışımda): aptal bir bileşen, "ana bileşen tarafından sahne aracılığıyla ne yapılacağını" anlatır ve bir şeylerin nasıl yapılacağını bilmez ama sahne kullanır yerine geri aramalar.
"Akıllı" bir örnek AvatarComponent:
class AvatarComponent extends Component {
expandAvatar () {
this.setState({ loading: true });
sendAjaxRequest(...).then(() => {
this.setState({ loading: false });
});
}
render () {
<div onClick={this.expandAvatar}>
<img src={this.props.username} />
</div>
}
}
"Aptal" örneği AvatarComponent:
class AvatarComponent extends Component {
render () {
<div onClick={this.props.onExpandAvatar}>
{this.props.loading && <div className="spinner" />}
<img src={this.props.username} />
</div>
}
}
Sonunda, "aptal", "vatansız" ve "saf" kelimelerin, çoğunlukla kullanım durumunuza bağlı olarak bazen üst üste gelebilecek, ancak zorunlu olarak değil, oldukça farklı kavramlar olduğunu söyleyebilirim.