Framework: ReactJS ================== .. image:: /logos/logo-react.png :scale: 35% :alt: Logo Angular :align: center .. |date| date:: .. |time| date:: %H:%M Documentación básica de ReactJS .. contents:: Índice Configuraciones ############### Instalar React ************** Paso 1: Tener instalado NodeJS desde su página oficial: https://nodejs.org/es/ Paso 2: Instalar React con npx desde la carpeta del proyecto: ``npx create-react-app nombre-proyecto`` Paso 3: Acceder a la carpeta del proyecto y ejecutarlo: ``npm start`` Paso 4: Se abre el navegador con la ruta: ``http://localhost:3000`` .. attention:: npx viene instalado con npm y es su versión en la nube. De modo que si necesitas un paquete y no deseas instalarlo en tu máquina utiliza npx en lugar de npm. Herramientas de desarrollo ************************** Existen una serie de herramientas útiles que se pueden instalar desde la tienda de tu navegador: - React Developer Tools También existe una herramienta muy útil para Visual Studio Code: - ES7 React/Redux/GraphQL/React-Native snippets Importar React desde CDN ************************ Existe la opción de importar react desde un cdn en lugar de crear un proyecto con node: .. code-block:: :linenos: React prueba
Estructura proyecto React ************************* - Carpeta Public: Aquí irá todo los archivos públicos como imágenes, iconos y algún que otro html. - Carpeta src: aquí viene el contenido del proyecto. - index.js: Archivo de inicio principal de la aplicación. Tiene su homónimo css disponible para los estilos globales. - App.js: Componente principal de la aplicación donde se irán cargando el resto de componentes. Dentro de src podemos crear la siguiente estructura de subcarpetas basado en Atomic Design: - common: para componentes que se van a reutilizar en distintos sitios de la aplicación. - templates: para componentes que pintan diferentes páginas en la aplicación. - Router.js: para los componentes que se relacionan con el enrutamiento (React Router). - pages: para los componentes que pintan vistas, dentro de esta carpeta se crean otras subcarpetas para componentes como Index, Login, Shop.. y dentro cada uno de sus componentes de un solo uso. - requests: para los archivos que consumen servicios rest. Preparar App.js *************** Se borra el contenido de **App.js** y **App.css** dentro de la carpeta src y se edita **App.js**: .. code-block:: :linenos: // Se importa el css si existe: import './App.css'; // se crea una función: function App() { // esta función retorna un nodo con todas las etiquetas html: return (

Soy un componente de prueba

); } // se exporta el componente como un módulo: export default App; .. note:: **index.js** se queda vinculado como nodo principal hacia el archivo **index.html** el resto irán ligados a **app.js** Componentes ########### Los componentes basados en funciones son los más modernos y recomendados para uso de **hooks**. Crear un componente ******************* Crear un componente: en **src** crear un archivo llamado **Prueba.js**: .. code-block:: :linenos: // se crea una función con el componente: function Prueba(){ // el retorno del componente será el contenido html: return(

Componente de prueba

); } export default Prueba; .. attention:: Por convención el nombre del componente comienza en Mayúscula y el contenido html de return irá siempre envuelto en etiquetas **
** Crear css del componente ************************ Además del css principal de **App.css** cada componente lleva su propio archivo css con el mismo nombre **Prueba.css**: .. code-block:: css :linenos: h1{ color: blue; } Utilizar componente ******************* Para utilizar el componente, es necesario cargarlo en otro componente que este funcionando, actualmente **App.js**: .. code-block:: :linenos: import './App.css'; // importar componente: import Prueba from './Prueba'; function App() { return (

Recuerda usar contenedores div sino dará errores

{/* cargar componente (metodo para hacer comentarios en el return): */}
); } export default App; Uso de fragment *************** Fragment te permite cargar varios nodos sin tener que añadir al DOM etiquetas div: .. code-block:: :linenos: // importar fragment: import {Fragment} from 'react'; import './App.css'; import Prueba from './Prueba'; function App() { return (

El tag fragment omite el uso de divs

); } export default App; Props: Comunicación de padre a hijo *********************************** Los props permiten enviar datos desde componentes padre a hijos Enviando propiedades ++++++++++++++++++++ - Editar el componente padre (en este ejemplo **App.js**): .. code-block:: :linenos: import {Fragment} from 'react'; import './App.css'; import Prueba from './Prueba'; function App() { return (

Listado de consolas:

); } export default App; Recuperando propiedades +++++++++++++++++++++++ Recuperar propiedades en el componente hijo (en este caso **Prueba.js**): .. code-block:: :linenos: import './Prueba.css'; import './Prueba.css'; // cargar propiedades (o bien escribimos props y sacamos props.marca, props.modelo o desestructuramos como en este caso): function Prueba({marca, modelo}){ return(
{/* Cargar la información: */}

- {marca} {modelo}

); } export default Prueba; Propiedades por defecto (default props) +++++++++++++++++++++++++++++++++++++++ Cuando no se reciben propiedades se pueden establecer algunas por defecto en el componente que completan uno o varios campos no recibidos: .. code-block:: :linenos: import './Prueba.css'; function Prueba({marca, modelo}){ return(

{marca} {modelo}

); } // si el componente no recibe propiedades añade estas: Prueba.defaultProps = {marca: "Genérica", modelo: "estandar"} export default Prueba; Validar propiedades (PropTypes) +++++++++++++++++++++++++++++++ Se pueden validar los campos recibidos, de manera que cuando uno no cumpla con el formato establecido nos avise por consola: .. code-block:: :linenos: // importar PropTypes: import PropTypes from 'prop-types'; import './Prueba.css'; function Prueba({marca, modelo, lanzamiento}){ return(

{marca} {modelo} de {lanzamiento}

); } // crear validador: Prueba.propTypes = { marca: PropTypes.string.isRequired, modelo: PropTypes.string, lanzamiento: PropTypes.number } export default Prueba; Comunicación de hijo a padre **************************** 1. Desde el componente hijo tenemos lo siguiente: .. code-block:: :linenos: // importar el hook: import {useState} from 'react'; import './Prueba.css'; // la función recibe un hook con los valores: function Prueba({setJuegos}){ // crear un nuevo hook para cambiar el estado del actual: const [nuevoJuego, setNuevoJuego] = useState(''); // el hook tendra un handle para cambiar su estado: const handleNuevoJuego = (e) => { setNuevoJuego(e.target.value); } // crear un handle que añadira el juego nuevo: const handleJuegos = (e) => { // recuerda prevenir refresco de pantalla: e.preventDefault(); // utilizar el hook del padre para añadir el valor del hook del hijo a una lista: setJuegos(juego => [...juego, nuevoJuego]); // regresar a su estado vacio el hook del hijo: setNuevoJuego(''); } // retornar el input donde introducir nuevos valores: return(
) } export default Prueba; 2. Y desde el padre: .. code-block:: :linenos: import {Fragment} from 'react'; // importar el hook: import {useState} from 'react'; // importar el hijo: import Prueba from './Prueba.js'; import './App.css'; function App() { // tenemos el hook principal con los juegos: const [juegos, setJuegos] = useState(['Zelda', 'Mario', 'Yoshi']); // en el return añadimos el componente al formulario y le pasamos el hook de juegos haciendo el cambio de estado: return(
    { juegos.map((juego, index) => { return
  • {juego}
  • }) }
) } export default App; .. note:: Se puede añadir un valor index en los mapeos para evitar errores de duplicate key JSX ### JSX es una combinación de la sintaxis de javascript con XML, similar a HTML. Imprimir datos en JSX ********************* .. code-block:: :linenos: import './Prueba.css'; // cargar propiedades (o bien escribimos props y sacamos props.marca, props.modelo o desestructuramos como en este caso): function Prueba(){ // crear una variable: const consola = { marca: "Nintendo", modelo: "DS" } return(
{/* Cargar la información: */}

- {consola.marca} {consola.modelo}

); } export default Prueba; Mostrar contenido de un objeto ****************************** .. code-block:: :linenos: import './Prueba.css'; function Prueba(){ const consola = { marca: "Nintendo", modelo: "DS", lanzamiento: 2001 } return(

Ver todos los valores de un objeto:

{/* ver valores del objeto (objeto, campos, cantidad de espacios): */}
{JSON.stringify(consola, null, 3)}

Ver solo campos determinados:

{JSON.stringify(consola, ['marca', 'modelo'], 5)}
); } export default Prueba; Condicionales en JSX ******************** Si es necesario hacer una validación dentro del return se hace del siguiente modo: Condicional simple ****************** .. code-block:: :linenos: import './Prueba.css'; function Prueba(){ const consola = { marca: "Nintendo", modelo: "DS", lanzamiento: 2001 } return(
{consola.marca === "Nintendo" &&

La consola es de Nintendo

}
); } export default Prueba; Condicional ternaria ******************** .. code-block:: :linenos: import './Prueba.css'; function Prueba(){ const consola = { marca: "Nintendo", modelo: "DS", lanzamiento: 2001 } return(
{consola.marca === "Nintendo" ? (

La consola es de Nintendo

) : (

La consola es otra marca

)}
); } export default Prueba; Estilos y clases **************** Añadir estilos manualmente con **style** ++++++++++++++++++++++++++++++++++++++++ .. code-block:: :linenos: import './Prueba.css'; function Prueba(){ // Utilizar la notación CamelCase en lugar de kebab-case para estilos: const estilo = { color: "red", backgroundColor: "black" } return(
{/* cargar datos de estilo: */}

Nintendo Switch

); } export default Prueba; uso de clases con className *************************** En JSX se reemplaza el atributo class por className: .. code-block:: :linenos: import './Prueba.css'; function Prueba(){ const lanzamiento = 2017; return(
{/* implementar clase: */}

Nintendo Switch

{/* uso ternario de clases condicionales: */}

Lanzamiento: {lanzamiento}

); } export default Prueba; Recorrer array con map ********************** .. code-block:: :linenos: import './Prueba.css'; function Prueba(){ const consolas = ["Nintendo Switch", "Gameboy", "Master System", "Playstation"]; return(
{/* recorrer elementos con map (importante añadir una key): */}
    { consolas.map( consola =>{ return
  1. {consola}
  2. }) }
); } export default Prueba; Recorrer array de objetos con map ********************************* .. code-block:: :linenos: import './Prueba.css'; function Prueba(){ const consolas = [ {marca: "Nintendo", modelo: "Switch"}, {marca: "Sega", modelo: "Master System"}, {marca: "Sony", modelo: "PlayStation"} ]; return( consolas.map( consola =>{ return(
) }) ); } export default Prueba; .. note:: Hemos añadido un segundo return para poder añadir más de una línea de JSX dentro del bucle. .. note:: Se puede desestructurar el elemento **consola** en **({marca, modelo})**. Eventos y Hooks ############### Tipos de Eventos **************** PORTAPAPELES ++++++++++++ - onCopy - onCut - onPaste TECLADO +++++++ - onKeyDown - onKeyUp - onKeyPress RATÓN +++++ - onClick - onContextMenu - onDoubleClick - onDrag - onDragEnd - onDragEnter - onDragExit - onDragLeave - onDragOver - onDragStart - onDrop - onMouseDown - onMouseEnter - onMouseLeave - onMouseMove - onMouseOut - onMouseOver - onMouseUp FORMULARIOS +++++++++++ - onChange - onInput - onInvalid - onReset - onSubmit mas eventos en: https://es.reactjs.org/docs/events.html Uso de eventos ************** Eventos sin retorno +++++++++++++++++++ .. code-block:: :linenos: import {Fragment} from 'react'; import './App.css'; function App() { // función que dispara el evento: const mensaje = (e) => { // lanzar mensaje con alguna propiedad del botón: alert(`se ha pulsado ${e.target.innerText}`); } return ( {/* botón con el evento click: */} ); } export default App; Eventos con retorno y parámetros ++++++++++++++++++++++++++++++++ .. code-block:: :linenos: import {Fragment} from 'react'; import './App.css'; function App() { // se recibén en el callback los parámetros: const consola = (marca, modelo) => { // los eventos que retornan algo también reciben algo: return (e) => { // ahora hay dos tipos de parámetros, los que se recibén de la función y el evento que se recibe en este caso en el return: // parametros recibidos: alert(`${marca} ${modelo}`); // evento recibido por return: alert(`se ha pulsado ${e.target.innerText}`); } } return ( {/* el evento recibe la función con los parámetros:: */} ); } export default App; Hooks ***** Los hooks se utilizan en React para cambiar el estado de un componente, los más comunes son: useState ++++++++ Devuelve un valor con estado y una función para actualizarlo: .. code-block:: :linenos: import {Fragment} from 'react'; // importar el hook: import {useState} from 'react'; import './App.css'; function App() { // el elemento consola será un hook con un valor por defecto: const [consola, setConsola] = useState("ej. Gameboy"); // a continuación se usará una función que ejecute el cambio de estado: const consolaChange = (e) => { // recuperar el valor del input: setConsola(e.target.value); } return (

¿Cuál es tu videoconsola favorita?

Mi videoconsola favorita es: {consola}

); } export default App; useEffect +++++++++ Realiza la ejecución de código después de renderizar la pantalla. Muy útil para subscribirse a servicios rest: .. code-block:: :linenos: // se importa useEffect: import {useState, useEffect} from 'react'; function App() { // se declara el hook tipo useState: const [mensaje, setMensaje] = useState(0); // el código de useEffect se ejecuta una vez renderizado el componente: useEffect( () => { // modificación de estado: window.setTimeout(()=>{ setMensaje(mensaje + 1); }, 1000); }, [mensaje] // este valor se dispara cuando detecta un cambio de estado ) return

{mensaje}

; } export default App; useContext ++++++++++ Crea un contexto por el que se pueden enviar propiedades a cualquier componente sin tener que enviarlo por parámetros: 1. Archivo que recibe el contexto **message.js**: .. code-block:: :linenos: // importar en el archivo React y el hook: import React, {useContext} from 'react'; // crear un mensaje: const mensaje = "Mensaje genérico"; // cargar en el contexto de React: const MensajeContext = React.createContext(mensaje); 2. Uso del contexto: .. code-block:: :linenos: function App() { // utilizar el context sin necesidad de hacer nada mas: const mensaje = useContext(MensajeContext); return

{mensaje}

; } export default App; Formularios en React #################### Combinando el uso de eventos y hooks se preparan los formularios .. code-block:: :linenos: import {Fragment} from 'react'; // importar el hook: import {useState} from 'react'; import './App.css'; function App() { // crear los hooks para el usuario y contraseña: const [usuario, setUsuario] = useState(''); const [password, setPassword] = useState(''); // cuando escribimos en el campo se irá cambiando su estado: const handleUsuario = (evento) =>{ // se recupera el evento: setUsuario(evento.target.value); console.log(evento.target.value); } const handlePassword = (evento) =>{ // se recupera el evento: setPassword(evento.target.value); } // Ejecutamos esta acción al hacer login: const login = (e) =>{ // para prevenir que refresque por defecto la página: e.preventDefault(); if(usuario === 'guillermo' && password === "1234"){ alert("Sesión iniciada correctamente"); }else{ alert("Error al iniciar sesión"); } } return ( <>
); } export default App; Rutas con React Router ###################### Para las rutas se utiliza un modulo llamado React Router Instalación *********** Instalar el módulo en el proyecto: ``npm install react-router-dom --save`` Crear archivo de rutas ********************** 1. Dentro de la carpeta **src** crear archivo **Router.js**: .. code-block:: :linenos: // importar funciones del modulo react router: import {BrowserRouter, Route, Routes} from 'react-router-dom'; // importar fragment también: import {Fragment} from 'react'; // importar los componentes de vista: import Inicio from './Inicio'; import Prueba from './Prueba'; import Error from './Error'; import Parametros from './Parametros'; function Router(){ // retornar la estructura de rutas: return( {/* Ruta raiz (necesita el atributo exact): */} } /> } /> {/* Ruta con parametros: */} } /> {/* Ruta para urls no establecidas (error 404): */} } /> ) } export default Router; 2. Cargar el enrutador en **App.js**: .. code-block:: :linenos: import {Fragment} from 'react'; import './App.css'; // importar router: import Router from './Router'; function App() { // cargar directamente el router en el return: return( ) } export default App; Recibir parámetros de una ruta ****************************** Recibir parametros en el controlador **Parametros.js**: .. code-block:: :linenos: // importar useParams de React Router: import { useParams } from 'react-router-dom'; function Parametros(){ // cargar un parametro mediante desestructuración: const {nombre} = useParams(); return(

Te llamas: {nombre}

) } export default Parametros; Crear Navbar con NavLink ************************ Con la función **NavLink** se crea la barra de navegación de nuestra aplicación, editamos **Router.js**: .. code-block:: :linenos: // importar función navlink: import {BrowserRouter, Route, Routes, NavLink} from 'react-router-dom'; // importar fragment también: import {Fragment} from 'react'; // importar los componentes de vista: import Inicio from './Inicio'; import Prueba from './Prueba'; import Error from './Error'; import Parametros from './Parametros'; function Router(){ // retornar la estructura de rutas: return( {/* cargamos el nav aquí: */} } /> } /> } /> } /> ) } export default Router; .. attention:: El atributo **activeClassName** define el nombre de la clase que se activa cuando esta la ruta activa. Solo hay que crear dicha clase en nuestro css y react router la reconocerá.