Saltar al contenido principal

React en ES6+

· 6 min de lectura
Traducción Beta No Oficial

Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →

Mientras rediseñábamos Instagram Web desde cero este año, disfrutamos usando varias características de ES6+ para escribir nuestros componentes de React. Permíteme destacar algunas formas en que estas nuevas características del lenguaje pueden transformar cómo escribes aplicaciones React, haciéndolo más fácil y divertido que nunca.

Clases

Sin duda, el cambio más visible en cómo escribimos componentes React con ES6+ ocurre cuando elegimos usar la sintaxis de definición de clases. En lugar de usar el método React.createClass para definir un componente, podemos definir una auténtica clase ES6 que extiende React.Component:

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

Inmediatamente notarás una diferencia sutil: una sintaxis más concisa está disponible al definir clases:

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() {}
}

En particular, hemos eliminado dos paréntesis y un punto y coma final, y por cada método declarado omitimos dos puntos, la palabra clave function y una coma.

Todos los métodos del ciclo de vida excepto uno pueden definirse como esperarías usando la nueva sintaxis de clases. El constructor de la clase ahora asume el rol que antes cumplía 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
}
}

Inicializadores de propiedades

En el mundo de las clases ES6+, los tipos y valores por defecto de las props existen como propiedades estáticas en la propia clase. Estos, junto con el estado inicial del componente, pueden definirse usando inicializadores de propiedades de 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,
}
}

Los inicializadores de propiedades de ES7 operan dentro del constructor de la clase, donde this se refiere a la instancia en construcción, por lo que el estado inicial aún puede depender de this.props. Notablemente, ya no necesitamos definir los valores por defecto de las props y el objeto de estado inicial mediante funciones getter.

Funciones de flecha

El método React.createClass solía realizar un enlace adicional en los métodos de instancia de tu componente para asegurar que, dentro de ellos, la palabra clave this hiciera referencia a la instancia del componente.

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});
},
});

Dado que no utilizamos React.createClass al definir componentes con la sintaxis de clases ES6+, parecería que necesitamos enlazar manualmente los métodos de instancia donde queramos este comportamiento:

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});
}
}

Afortunadamente, combinando dos características de ES6+ – funciones de flecha e inicializadores de propiedades – el enlace opcional a la instancia del componente se vuelve pan comido:

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

El cuerpo de las funciones de flecha ES6 comparte el mismo this léxico que el código que las rodea, lo que nos da el resultado deseado debido al alcance de los inicializadores de propiedades ES7. Mira bajo el capó para entender por qué funciona.

Nombres de propiedades dinámicos y plantillas de cadena

Una de las mejoras en los literales de objetos incluye la capacidad de asignar a un nombre de propiedad derivado. Originalmente podríamos haber hecho algo así para establecer un estado:

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

Ahora tenemos la capacidad de construir objetos cuyos nombres de propiedad se determinan mediante una expresión JavaScript en tiempo de ejecución. Aquí usamos una cadena de plantilla para determinar qué propiedad establecer en el estado:

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

Desestructuración y atributos de propagación

Al componer componentes, a menudo queremos pasar la mayoría de las props de un componente padre a un componente hijo, pero no todas. Al combinar la desestructuración de ES6+ con los atributos de propagación de JSX, esto se vuelve posible sin ceremonias:

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>
);
}
}

Podemos combinar atributos de propagación JSX con atributos regulares, aprovechando una regla simple de precedencia para implementar sobreescrituras y valores predeterminados. Este elemento adquirirá el className "override" incluso si existe una propiedad className en this.props:

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

</div>

Este elemento normalmente tendrá el className "base" a menos que exista una propiedad className en this.props que lo sobrescriba:

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

</div>

Gracias por leer

Espero que disfrutes usando las características de ES6+ para escribir código React tanto como nosotros. Gracias a mis colegas por sus contribuciones a esta publicación, y gracias especialmente al equipo de Babel por hacer el futuro disponible para todos nosotros hoy.