Vai al contenuto principale

React su ES6+

· Lettura di 6 min
Traduzione Beta Non Ufficiale

Questa pagina è stata tradotta da PageTurner AI (beta). Non ufficialmente approvata dal progetto. Hai trovato un errore? Segnala problema →

Durante la riprogettazione di Instagram Web da zero quest'anno, abbiamo apprezzato l'utilizzo di numerose funzionalità ES6+ per scrivere i nostri componenti React. Mi sia consentito evidenziare alcuni modi in cui queste nuove caratteristiche del linguaggio possono trasformare il modo in cui scrivi un'app React, rendendola più semplice e divertente che mai.

Classi

Di gran lunga, il cambiamento più visibile nel modo in cui scriviamo componenti React con ES6+ si manifesta quando scegliamo di utilizzare la sintassi di definizione delle classi. Invece di usare il metodo React.createClass per definire un componente, possiamo definire una vera e propria classe ES6 che estende React.Component:

JavaScript
class Photo extends React.Component {
render() {
return <img alt={this.props.caption} src={this.props.src} />;
}
}

Immediatamente noterai una differenza sottile – è disponibile una sintassi più concisa quando definisci le classi:

JavaScript
// The ES5 way
var Photo = React.createClass({
handleDoubleTap: function(e) {},
render: function() {},
});
JavaScript
// The ES6+ way
class Photo extends React.Component {
handleDoubleTap(e) {}
render() {}
}

In particolare, abbiamo eliminato due parentesi e un punto e virgola finale, e per ogni metodo dichiarato omettiamo due punti, la parola chiave function e una virgola.

Tutti i metodi del ciclo di vita tranne uno possono essere definiti come ti aspetteresti usando la nuova sintassi delle classi. Il constructor della classe assume ora il ruolo precedentemente ricoperto da componentWillMount:

JavaScript
// The ES5 way
var EmbedModal = React.createClass({
componentWillMount: function() {},
});
JavaScript
// The ES6+ way
class EmbedModal extends React.Component {
constructor(props) {
super(props);
// Operations usually carried out in componentWillMount go here
}
}

Inizializzatori di proprietà

Nel mondo delle classi ES6+, i tipi delle proprietà (prop types) e i valori predefiniti risiedono come proprietà statiche sulla classe stessa. Questi, insieme allo stato iniziale del componente, possono essere definiti usando gli inizializzatori di proprietà ES7:

JavaScript
// The ES5 way
var Video = React.createClass({
getDefaultProps: function() {
return {
autoPlay: false,
maxLoops: 10,
};
},
getInitialState: function() {
return {
loopsRemaining: this.props.maxLoops,
};
},
propTypes: {
autoPlay: React.PropTypes.bool.isRequired,
maxLoops: React.PropTypes.number.isRequired,
posterFrameSrc: React.PropTypes.string.isRequired,
videoSrc: React.PropTypes.string.isRequired,
},
});
JavaScript
// The ES6+ way
class Video extends React.Component {
static defaultProps = {
autoPlay: false,
maxLoops: 10,
}
static propTypes = {
autoPlay: React.PropTypes.bool.isRequired,
maxLoops: React.PropTypes.number.isRequired,
posterFrameSrc: React.PropTypes.string.isRequired,
videoSrc: React.PropTypes.string.isRequired,
}
state = {
loopsRemaining: this.props.maxLoops,
}
}

Gli inizializzatori di proprietà ES7 operano all'interno del costruttore della classe, dove this si riferisce all'istanza della classe in costruzione, quindi lo stato iniziale può ancora dipendere da this.props. Significativamente, non dobbiamo più definire i valori predefiniti delle proprietà e l'oggetto dello stato iniziale tramite una funzione getter.

Funzioni freccia

Il metodo React.createClass eseguiva un lavoro extra di binding sui metodi d'istanza del tuo componente per garantire che, al loro interno, la parola chiave this si riferisse all'istanza del componente in questione.

JavaScript
// Autobinding, brought to you by React.createClass
var PostInfo = React.createClass({
handleOptionsButtonClick: function(e) {
// Here, 'this' refers to the component instance.
this.setState({showOptionsModal: true});
},
});

Poiché non coinvolgiamo il metodo React.createClass quando definiamo componenti usando la sintassi delle classi ES6+, sembrerebbe che dobbiamo eseguire manualmente il binding dei metodi d'istanza ovunque vogliamo questo comportamento:

JavaScript
// Manually bind, wherever you need to
class PostInfo extends React.Component {
constructor(props) {
super(props);
// Manually bind this method to the component instance...
this.handleOptionsButtonClick = this.handleOptionsButtonClick.bind(this);
}
handleOptionsButtonClick(e) {
// ...to ensure that 'this' refers to the component instance here.
this.setState({showOptionsModal: true});
}
}

Fortunatamente, combinando due funzionalità ES6+ – le funzioni freccia e gli inizializzatori di proprietà – l'opt-in per il binding all'istanza del componente diventa un gioco da ragazzi:

JavaScript
class PostInfo extends React.Component {
handleOptionsButtonClick = (e) => {
this.setState({showOptionsModal: true});
}
}

Il corpo delle funzioni freccia ES6 condivide lo stesso this lessicale del codice che le circonda, ottenendo così il risultato desiderato grazie al modo in cui sono definiti gli ambiti degli inizializzatori di proprietà ES7. Dai un'occhiata sotto il cofano per capire perché funziona.

Nomi di proprietà dinamici e template string

Uno dei miglioramenti agli oggetti letterali include la possibilità di assegnare un nome di proprietà derivato. In origine avremmo potuto fare qualcosa del genere per impostare uno stato:

JavaScript
var Form = React.createClass({
onChange: function(inputName, e) {
var stateToSet = {};
stateToSet[inputName + 'Value'] = e.target.value;
this.setState(stateToSet);
},
});

Ora possiamo costruire oggetti i cui nomi delle proprietà sono determinati da un'espressione JavaScript a runtime. Qui usiamo una stringa template per determinare quale proprietà impostare nello stato:

JavaScript
class Form extends React.Component {
onChange(inputName, e) {
this.setState({
[`${inputName}Value`]: e.target.value,
});
}
}

Destrutturazione e attributi spread

Spesso quando componiamo componenti, potremmo voler passare la maggior parte delle proprietà di un componente genitore a un componente figlio, ma non tutte. Combinando la destrutturazione ES6+ con gli attributi spread di JSX, questo diventa possibile senza cerimonie:

JavaScript
class AutoloadingPostsGrid extends React.Component {
render() {
const {
className,
...others // contains all properties of this.props except for className
} = this.props;
return (
<div className={className}>
<PostsGrid {...others} />
<button onClick={this.handleLoadMoreClick}>Load more</button>
</div>
);
}
}

Possiamo combinare gli attributi spread di JSX anche con attributi regolari, sfruttando una semplice regola di precedenza per implementare override e valori predefiniti. Questo elemento acquisirà il className "override" anche se esiste una proprietà className in this.props:

JavaScript
<div {...this.props} className="override">

</div>

Questo elemento avrà normalmente il className "base" a meno che non esista una proprietà className in this.props per sovrascriverlo:

JavaScript
<div className="base" {...this.props}>

</div>

Grazie per la lettura

Spero che vi divertiate a utilizzare le funzionalità di ES6+ per scrivere codice React tanto quanto noi. Ringrazio i miei colleghi per i contributi a questo post, e un ringraziamento speciale al team di Babel per aver reso il futuro accessibile a tutti noi, oggi.