Come decidi tu, come scegliere tra questi tre in base allo scopo / dimensione / oggetti di scena / comportamento dei nostri componenti?
L'estensione da React.PureComponent
o verso React.Component
con un shouldComponentUpdate
metodo personalizzato ha implicazioni sulle prestazioni. L'uso di componenti funzionali senza stato è una scelta "architettonica" e non ha alcun vantaggio prestazionale pronto all'uso (ancora).
Per componenti semplici, solo di presentazione che devono essere facilmente riutilizzati, preferisci i componenti funzionali senza stato. In questo modo sei sicuro che siano disaccoppiati dall'attuale logica dell'app, che sono estremamente facili da testare e che non hanno effetti collaterali imprevisti. L'eccezione è se per qualche motivo ne hai molti o se hai davvero bisogno di ottimizzare il loro metodo di rendering (come non puoi definire shouldComponentUpdate
per un componente funzionale senza stato).
Estendi PureComponent
se sai che il tuo output dipende da semplici oggetti di scena / stato ("semplice" significa che nessuna struttura di dati nidificata, poiché PureComponent esegue un confronto superficiale) E hai bisogno / puoi ottenere alcuni miglioramenti delle prestazioni.
Estendi Component
e implementa il tuo shouldComponentUpdate
se hai bisogno di alcuni miglioramenti delle prestazioni eseguendo una logica di confronto personalizzata tra oggetti di scena successivi / attuali e stato. Ad esempio, puoi eseguire rapidamente un confronto approfondito utilizzando lodash # isEqual:
class MyComponent extends Component {
shouldComponentUpdate (nextProps, nextState) {
return !_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState);
}
}
Inoltre, implementare le proprie shouldComponentUpdate
o estenderle PureComponent
sono ottimizzazioni, e come al solito dovresti iniziare a esaminarle solo se hai problemi di prestazioni ( evita le ottimizzazioni premature ). Come regola generale, provo sempre a fare queste ottimizzazioni dopo che l'applicazione è funzionante, con la maggior parte delle funzionalità già implementate. È molto più facile concentrarsi sui problemi di prestazioni quando effettivamente si frappongono.
Più dettagli
Componenti funzionali senza stato:
Questi sono definiti semplicemente usando una funzione. Poiché non esiste uno stato interno per un componente senza stato, l'output (ciò che viene reso) dipende solo dai puntelli forniti come input per questa funzione.
Professionisti:
Il modo più semplice possibile per definire un componente in React. Se non è necessario gestire alcuno stato, perché preoccuparsi delle classi e dell'eredità? Una delle principali differenze tra una funzione e una classe è che con la funzione si è certi che l'output dipende solo dall'input (non dalla cronologia delle precedenti esecuzioni).
Idealmente nella tua app dovresti mirare ad avere il maggior numero possibile di componenti senza stato, perché ciò normalmente significa che hai spostato la tua logica al di fuori del livello di visualizzazione e spostata in qualcosa come Redux, il che significa che puoi testare la tua vera logica senza dover eseguire il rendering di nulla (molto più facile da testare, più riutilizzabile, ecc.).
Contro:
Nessun metodo del ciclo di vita. Non hai modo di definire componentDidMount
e altri amici. Normalmente lo fai all'interno di un componente superiore nella gerarchia in modo da poter trasformare tutti i bambini in apolidi.
Non è possibile controllare manualmente quando è necessario un nuovo rendering, poiché non è possibile definire shouldComponentUpdate
. Un nuovo rendering avviene ogni volta che il componente riceve nuovi oggetti di scena (nessun modo per confrontare superficialmente, ecc.). In futuro, React potrebbe ottimizzare automaticamente i componenti senza stato, per ora ci sono alcune librerie che puoi usare. Poiché i componenti senza stato sono solo funzioni, in pratica è il classico problema della "memorizzazione delle funzioni".
I riferimenti non sono supportati: https://github.com/facebook/react/issues/4936
Un componente che estende la classe PureComponent VS Un componente normale che estende la classe Component:
React era solito avere un PureRenderMixin
che potevi associare a una classe definita usando la React.createClass
sintassi. Il mixin semplicemente definirebbe un shouldComponentUpdate
confronto superficiale tra i props successivi e lo stato successivo per verificare se qualcosa è cambiato. Se non cambia nulla, non è necessario eseguire un nuovo rendering.
Se si desidera utilizzare la sintassi ES6, non è possibile utilizzare i mixin. Quindi per comodità React ha introdotto una PureComponent
classe che puoi ereditare invece di usare Component
. PureComponent
implementa semplicemente shouldComponentUpdate
allo stesso modo di PureRendererMixin
. È principalmente una cosa comoda, quindi non è necessario implementarlo da soli, poiché un confronto superficiale tra lo stato attuale / successivo e gli oggetti di scena è probabilmente lo scenario più comune che può darti alcune prestazioni veloci.
Esempio:
class UserAvatar extends Component {
render() {
return <div><img src={this.props.imageUrl} /> {{ this.props.username }} </div>
}
}
Come puoi vedere, l'output dipende da props.imageUrl
e props.username
. Se in un componente genitore esegui il rendering <UserAvatar username="fabio" imageUrl="http://foo.com/fabio.jpg" />
con gli stessi puntelli, React chiamerebbe render
ogni volta, anche se l'output sarà esattamente lo stesso. Ricorda però che React implementa dom diffing, quindi il DOM non verrebbe effettivamente aggiornato. Tuttavia, eseguire il diff di dom può essere costoso, quindi in questo scenario sarebbe uno spreco.
Se invece il UserAvatar
componente si estende PureComponent
, viene eseguito un confronto superficiale. E poiché oggetti di scena e nextProps sono uguali, render
non verranno chiamati affatto.
Note sulla definizione di "puro" in React:
In generale, una "funzione pura" è una funzione che valuta sempre lo stesso risultato dato lo stesso input. L'output (per React, questo è ciò che viene restituito dal render
metodo) non dipende da alcuna storia / stato e non ha effetti collaterali (operazioni che cambiano il "mondo" al di fuori della funzione).
In React, i componenti senza stato non sono necessariamente componenti puri secondo la definizione precedente se si chiama "senza stato" un componente che non chiama this.setState
e che non utilizza this.state
.
In effetti, in a PureComponent
, è ancora possibile eseguire effetti collaterali durante i metodi del ciclo di vita. Ad esempio, è possibile inviare una richiesta Ajax all'interno componentDidMount
oppure eseguire alcuni calcoli DOM per regolare dinamicamente l'altezza di un div all'interno render
.
La definizione di "Componenti stupidi" ha un significato più "pratico" (almeno nella mia comprensione): un componente stupido "viene detto" cosa fare da un componente genitore tramite oggetti di scena e non sa come fare le cose ma usa oggetti di scena callbacks invece.
Esempio di "intelligente" 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>
}
}
Esempio di "stupido" AvatarComponent
:
class AvatarComponent extends Component {
render () {
<div onClick={this.props.onExpandAvatar}>
{this.props.loading && <div className="spinner" />}
<img src={this.props.username} />
</div>
}
}
Alla fine direi che "stupido", "apolide" e "puro" sono concetti abbastanza diversi che a volte possono sovrapporsi, ma non necessariamente, a seconda principalmente del caso d'uso.