Es una librería JavaScript de código abierto enfocada a la visualización.
Permite el desarrollo de interfaces de usuario de forma sencilla, mediante componentes interactivos y reutilizables.
Sirve para desarrollar aplicaciones web de manera más ordenada y con menos código que si se utiliza Javascript puro o librerías como jQuery centradas en la manipulación del DOM.
const elemento = Hola, mundo!
;
Esta sintaxis de etiquetas no es ni un string ni HTML. Se llama JSX, y es una extensión de la sintaxis de JavaScript. Si bien no es requerido su uso con React, se recomienda hacerlo para describir cómo debería ser la interfaz de usuario.
const nombre = 'Juan Perez';
const elemento = Hola, {nombre}
;
Se puede poner cualquier expresión JavaScript dentro de llaves en JSX. Por ejemplo, 2 + 2, usuario.nombre, o formatearNombre(usuario).
Puede usarse dentro de declaraciones if, loops, asignarlo a variables, aceptarlo como argumento, y retornarlo desde dentro de funciones:
function obtenerSaludo(usuario) {
if (usuario) {
return Hola, {formatearNombre(usuario)}!
;
}
return Hola, Extraño.
;
}
Se pueden usar comillas para especificar strings literales como atributos:
También se pueden usar llaves para insertar una expresión JavaScript en un atributo:
Aunque si la etiqueta no contiene hijos, se puede cerrar inmediatamente con />:
Dado que JSX es más cercano a JavaScript que a HTML, se usa la convención de nomenclatura camelCase (tabIndex) en vez de nombres de atributos HTML. A su vez, el atributo class se vuelve className en JSX, dado que class, como veremos, es palabra reservada.
Los componentes permiten separar la interfaz de usuario en piezas independientes, reutilizables y pensar en cada pieza de forma aislada.
Conceptualmente, los componentes son como las funciones de JavaScript. Aceptan entradas (llamadas “props”) y devuelven elementos que describen lo que debe aparecer en la pantalla.
La forma más sencilla de definir un componente es escribir una función de JavaScript:
function Bienvenida(props) {
return Hola, {props.nombre}
;
}
Esta función es un componente de React válido porque acepta un solo argumento “props” con datos y devuelve un elemento de React. Llamamos a dichos componentes “funcionales” porque literalmente son funciones JavaScript.
También se puede utilizar una clase para definir un componente:
class Bienvenida extends React.Component {
render() {
return Hola, {this.props.nombre}
;
}
}
Los dos componentes anteriores son equivalentes desde el punto de vista de React.
Como se puede ver, para acceder a las props de un componente clase, es necesario usar this.props. El this refiere a un elemento JavaScript, dependiendo del contexto en el que se encuentra. En este caso de componentes clase, refiere a la clase (o a un objeto de esa clase).
Anteriormente, sólo encontramos elementos de React que representan las etiquetas del DOM:
Los elementos también pueden representar componentes definidos por el usuario:
Cuando React ve un elemento representando un componente definido por el usuario, pasa atributos JSX e hijos a este componente como un solo objeto. Llamamos a este objeto “props”. Por ejemplo, para el componente Bienvenida definido anteriormente, este código muestra “Hola, Sara” en la página:
Como se vio, los componentes pueden referirse a otros en su salida. Así, podemos crear un componente App que renderiza Bienvenida muchas veces:
Cada vez que cambie una prop del componente, el método render se invocará, actualizando la interfaz. Pero un componente no puede modificar sus propias props. Que cambien significa que el componente padre le pase otros valores como props.
Ya sea que declares un componente como una función o como una clase, las props son de solo lectura. No ocurre lo mismo con el estado (state) de un componente, como veremos a continuación.
El estado es similar a las props, pero es privado y está completamente controlado por el componente.
Vamos a implementar un componente Reloj que se actualice cada un segundo para mostrar la hora.
Para usar estado, se debe especificar el constructor de la clase y definir el estado en el mismo, de la forma:
class Reloj extends React.Component {
constructor(props) {
super(props);
this.state = {fecha: new Date()};
}
render() {
return (
Hola, mundo!
);
}
}
Hemos definido el estado pero no lo hemos usado aún. Vamos a mostrar en pantalla el estado:
class Reloj extends React.Component {
constructor(props) {
super(props);
this.state = {fecha: new Date()};
}
render() {
return (
Hola, mundo!
Son las {this.state.fecha.toLocaleTimeString()}.
);
}
}
Como se pudo ver, se hace de la misma forma que para las props, pero usando state.
Queremos configurar un temporizador cada vez que Reloj se renderice en el DOM por primera vez. Esto se llama «montaje» en React. También queremos borrar ese temporizador cada vez que el DOM producido por Reloj se elimine. Esto se llama «desmontaje» en React. Podemos declarar métodos especiales en la clase del componente para ejecutar algún código cuando un componente se monta y desmonta:
class Reloj extends React.Component {
constructor(props) {
super(props);
this.state = {fecha: new Date()};
}
componentDidMount() {
}
componentWillUnmount() {
}
render() {
return (
Hola, mundo!
Son las {this.state.fecha.toLocaleTimeString()}.
);
}
}
Estos métodos son llamados «métodos de ciclo de vida» del componente (lifecycle methods).
El método componentDidMount() se ejecuta después que la salida del componente ha sido renderizada en el DOM. Este es un buen lugar para configurar un temporizador:
componentDidMount() {
this.idTemporizador = setInterval(
() => this.tick(),
1000
);
}
Notar cómo guardamos el ID del temporizador en this (this.idTemporizador). Si bien this.props es configurado por el mismo React y this.state tiene un significado especial, se puede añadir campos adicionales a la clase manualmente si se necesita almacenar algo que no participa en el flujo de datos (como el ID de un temporizador).
Eliminaremos el temporizador en el método de ciclo de vida componentWillUnmount():
componentWillUnmount() {
clearInterval(this.idTemporizador);
}
Finalmente, implementaremos el método tick() que Reloj ejecutará cada segundo. Utilizará this.setState() para actualizar el estado del componente.
De esta forma, al cambiar el estado, el componente se actualiza y se invoca el método render, provocando que se actualice la interfaz.
Si bien el estado es local al componente y solo éste puede leerlo o modificarlo, un componente puede pasar como prop el valor de su estado a un componente hijo. El componente hijo no tiene forma de saber que ese valor viene del estado del componente padre. Simplemente, lo usa como prop (solo lectura).
A esto comúnmente se le llama flujo de datos «descendente» o «unidireccional». Cualquier estado siempre es propiedad de algún componente específico, y cualquier dato o interfaz de usuario derivados de ese estado solo pueden afectar a los componentes «debajo» de ellos en el árbol.
Los eventos son acciones que ocurren y provocan algún cambio o notificación en el Sistema.
Cuando programamos nuestra página, nosotros decidimos sobre qué eventos queremos reaccionar y cómo.
Existen muchos tipos de eventos distintos, por ejemplo:
Para detectar el evento click se puede utilizar la propiedad onClick de los elementos:
manejadorClick es una función definida dentro de la clase. Para que funcione, es necesario hacer un bind en el constructor:
this.manejadorClick = this.manejadorClick.bind(this);
Una forma de evitar hacer el bind, es utilizar Funciones Flecha:
Este código es equivalente al anterior, ahorrando la necesidad de hacer el bind en el constructor.
Por esto, de ahora en adelante, usaremos funciones flecha.
Muchas veces vamos a precisar mandar parámetros extra a la función que maneja el evento, por ejemplo, un identificador.
La función eliminarFila va a recibir 2 parámetros:
En React, se pueden crear distintos componentes que encapsulen el comportamiento que se quiere.
Se puede renderizar algunos de ellos, dependiendo del estado de la aplicación.
Esto hace que no siempre se vea lo mismo, sino que dependiendo del estado de la aplicación se va a ver un componente u otro.
Para hacer esto, se puede usar el operador if
Supongamos que tenemos estos dos componentes:
y queremos que se vea uno u otro dependiendo si el usuario está registrado o es un invitado.
Vamos a crear un un componente Bienvenida que mueste el mensaje adecuado:
Una alternativa al operador if es utilizar el Operador Condicional Ternario que brinda javascript:
Este código es equivalente al recién visto, donde:
condición ? verdadero : falso
Se pueden usar variables para almacenar elementos.
Sirve para renderizar condicionalmente una parte del componente mientras el resto del resultado no cambia.
Supongamos que tenemos dos botones, para iniciar y cerrar sesión respectivamente:
Vamos a crear un componente con estado, llamado ControlSesion.
El componente va a renderizar BotonIniciarSesion o BotonCerrarSesion dependiendo de su estado actual. También va a renderizar Bienvenida del ejemplo anterior.
Notar que usamos las funciones flecha para evitar el bind y en lugar del if usamos el Operador Ternario.
Declarar una variable y usar if es una buena forma de renderizar condicionalmente un componente pero también hay formas de hacer condiciones en una sola línea en JSX.
Para incluir expresiones en JSX hay que envolver el código con las llaves "{ }". Para incluir condicionalmente un elemento puede ser útil usar el operador lógico && de JavaScript.
En este caso, solo se muestra la cantidad de mensajes sin leer si se tiene al menos 1 mensaje sin leer.
Esto funciona porque en JavaScript:
Por eso, si la condición es true, el elemento justo después de && aparecerá en el resultado. Si es false, React lo ignorará.