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.PureComponent
veya 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.Component
shouldComponentUpdate
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 ( shouldComponentUpdate
vatansı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 Component
ve 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 shouldComponentUpdate
veya genişletmek PureComponent
optimizasyonlardı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 componentDidMount
ve 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 PureRenderMixin
kullanmakta tanımlanan bir sınıfa eklemek olabilir React.createClass
sö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 PureComponent
kullanmak yerine kalıtım yoluyla alabileceğiniz bir sınıf tanıttı Component
. PureComponent
sadece shouldComponentUpdate
aynı ş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.imageUrl
ve 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 UserAvatar
bileşen uzanır PureComponent
yerine, 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, render
yö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.setState
ve 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, PureComponent
yaşam döngüsü yöntemleri sırasında hala yan etkiler yapabilirsiniz. Örneğin, içine bir ajax isteği gönderebilir componentDidMount
veya 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.