Framework: ReactJS
Contents
Framework: ReactJS#

Documentación básica de ReactJS
Í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
Atención
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:
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <title>React prueba</title>
7
8</head>
9<body>
10 <div id="raiz"></div>
11
12 <script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
13 <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
14 <!-- React utiliza babel para poder trabajar con JSX -->
15 <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.18.13/babel.min.js"></script>
16 <!-- Definimos que el tipo de script será de babel: -->
17 <script type="text/babel">
18 const raiz = document.querySelector('#raiz');
19 const nombre = "Guillermo";
20 // Las llaves nos permiten incrustar código JSX:
21 const titulo = <h1>Te llamas {nombre}</h1>;
22
23 ReactDOM.render(titulo, raiz);
24 </script>
25</body>
26</html>
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:
1// Se importa el css si existe:
2import './App.css';
3
4// se crea una función:
5function App() {
6// esta función retorna un nodo con todas las etiquetas html:
7return (
8 <h1>Soy un componente de prueba</h1>
9);
10}
11
12// se exporta el componente como un módulo:
13export default App;
Nota
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:
1// se crea una función con el componente:
2function Prueba(){
3 // el retorno del componente será el contenido html:
4 return(
5 <div>
6 <h1>Componente de prueba</h1>
7 </div>
8 );
9}
10
11export default Prueba;
Atención
Por convención el nombre del componente comienza en Mayúscula y el contenido html de return irá siempre envuelto en etiquetas <div>
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:
1h1{
2 color: blue;
3}
Utilizar componente#
Para utilizar el componente, es necesario cargarlo en otro componente que este funcionando, actualmente App.js:
1import './App.css';
2// importar componente:
3import Prueba from './Prueba';
4
5function App() {
6return (
7 <div>
8 <h1>Recuerda usar contenedores div sino dará errores</h1>
9 {/* cargar componente (metodo para hacer comentarios en el return): */}
10 <Prueba />
11 </div>
12);
13}
14
15export default App;
Uso de fragment#
Fragment te permite cargar varios nodos sin tener que añadir al DOM etiquetas div:
1// importar fragment:
2import {Fragment} from 'react';
3import './App.css';
4import Prueba from './Prueba';
5
6function App() {
7return (
8 <Fragment>
9 <h1>El tag fragment omite el uso de divs</h1>
10 <Prueba />
11 </Fragment>
12);
13}
14
15export 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):
1import {Fragment} from 'react';
2import './App.css';
3import Prueba from './Prueba';
4
5function App() {
6return (
7 <Fragment>
8 <h1>Listado de consolas: </h1>
9 <Prueba marca="Nintendo" modelo="Wii" />
10 <Prueba marca="Nintendo" modelo="Switch" />
11 <Prueba marca="Nintendo" modelo="Gamecube" />
12 </Fragment>
13);
14}
15
16export default App;
Recuperando propiedades#
Recuperar propiedades en el componente hijo (en este caso Prueba.js):
1import './Prueba.css';
2
3import './Prueba.css';
4
5// cargar propiedades (o bien escribimos props y sacamos props.marca, props.modelo o desestructuramos como en este caso):
6function Prueba({marca, modelo}){
7
8 return(
9 <div>
10 {/* Cargar la información: */}
11 <h1>- {marca} {modelo}</h1>
12 </div>
13 );
14}
15
16export 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:
1import './Prueba.css';
2
3function Prueba({marca, modelo}){
4 return(
5 <div>
6 <p> {marca} {modelo}</p>
7 </div>
8 );
9}
10
11// si el componente no recibe propiedades añade estas:
12Prueba.defaultProps = {marca: "Genérica", modelo: "estandar"}
13
14export 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:
1// importar PropTypes:
2import PropTypes from 'prop-types';
3import './Prueba.css';
4
5function Prueba({marca, modelo, lanzamiento}){
6 return(
7 <div>
8 <p> {marca} {modelo} de {lanzamiento}</p>
9 </div>
10 );
11}
12
13// crear validador:
14Prueba.propTypes = {
15 marca: PropTypes.string.isRequired,
16 modelo: PropTypes.string,
17 lanzamiento: PropTypes.number
18}
19
20export default Prueba;
Comunicación de hijo a padre#
Desde el componente hijo tenemos lo siguiente:
1// importar el hook:
2import {useState} from 'react';
3import './Prueba.css';
4
5// la función recibe un hook con los valores:
6function Prueba({setJuegos}){
7 // crear un nuevo hook para cambiar el estado del actual:
8 const [nuevoJuego, setNuevoJuego] = useState('');
9
10 // el hook tendra un handle para cambiar su estado:
11 const handleNuevoJuego = (e) => {
12 setNuevoJuego(e.target.value);
13 }
14
15 // crear un handle que añadira el juego nuevo:
16 const handleJuegos = (e) => {
17 // recuerda prevenir refresco de pantalla:
18 e.preventDefault();
19 // utilizar el hook del padre para añadir el valor del hook del hijo a una lista:
20 setJuegos(juego => [...juego, nuevoJuego]);
21 // regresar a su estado vacio el hook del hijo:
22 setNuevoJuego('');
23 }
24
25 // retornar el input donde introducir nuevos valores:
26 return(
27 <form onSubmit={handleJuegos}>
28 <input type="text" value={nuevoJuego} onChange={handleNuevoJuego} />
29 </form>
30 )
31}
32
33export default Prueba;
Y desde el padre:
1import {Fragment} from 'react';
2// importar el hook:
3import {useState} from 'react';
4// importar el hijo:
5import Prueba from './Prueba.js';
6import './App.css';
7
8function App() {
9// tenemos el hook principal con los juegos:
10const [juegos, setJuegos] = useState(['Zelda', 'Mario', 'Yoshi']);
11
12// en el return añadimos el componente al formulario y le pasamos el hook de juegos haciendo el cambio de estado:
13return(
14 <Fragment>
15 <Prueba setJuegos={setJuegos} />
16 <ul>
17 {
18 juegos.map((juego, index) => {
19 return <li key={index}>{juego}</li>
20 })
21 }
22 </ul>
23 </Fragment>
24)
25
26}
27
28export default App;
Nota
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#
1import './Prueba.css';
2
3// cargar propiedades (o bien escribimos props y sacamos props.marca, props.modelo o desestructuramos como en este caso):
4function Prueba(){
5 // crear una variable:
6 const consola = {
7 marca: "Nintendo",
8 modelo: "DS"
9 }
10
11 return(
12 <div>
13 {/* Cargar la información: */}
14 <h1>- {consola.marca} {consola.modelo}</h1>
15 </div>
16 );
17}
18
19export default Prueba;
Mostrar contenido de un objeto#
1import './Prueba.css';
2
3function Prueba(){
4 const consola = {
5 marca: "Nintendo",
6 modelo: "DS",
7 lanzamiento: 2001
8 }
9
10 return(
11 <div>
12 <h1>Ver todos los valores de un objeto:</h1>
13 {/* ver valores del objeto (objeto, campos, cantidad de espacios): */}
14 <pre>{JSON.stringify(consola, null, 3)}</pre>
15 <hr/>
16 <h1>Ver solo campos determinados:</h1>
17 <pre>{JSON.stringify(consola, ['marca', 'modelo'], 5)}</pre>
18 </div>
19 );
20}
21
22export default Prueba;
Condicionales en JSX#
Si es necesario hacer una validación dentro del return se hace del siguiente modo:
Condicional simple#
1import './Prueba.css';
2
3function Prueba(){
4 const consola = {
5 marca: "Nintendo",
6 modelo: "DS",
7 lanzamiento: 2001
8 }
9
10 return(
11 <div>
12 {consola.marca === "Nintendo" &&
13 <p>La consola es de Nintendo</p>
14 }
15 </div>
16 );
17}
18
19export default Prueba;
Condicional ternaria#
1import './Prueba.css';
2
3function Prueba(){
4 const consola = {
5 marca: "Nintendo",
6 modelo: "DS",
7 lanzamiento: 2001
8 }
9
10 return(
11 <div>
12 {consola.marca === "Nintendo" ? (
13 <p>La consola es de Nintendo</p>
14 ) : (
15 <p>La consola es otra marca</p>
16 )}
17 </div>
18 );
19}
20
21export default Prueba;
Estilos y clases#
Añadir estilos manualmente con style#
1import './Prueba.css';
2
3function Prueba(){
4 // Utilizar la notación CamelCase en lugar de kebab-case para estilos:
5 const estilo = {
6 color: "red",
7 backgroundColor: "black"
8 }
9
10 return(
11 <div>
12 {/* cargar datos de estilo: */}
13 <p style={estilo}>Nintendo Switch</p>
14 </div>
15 );
16}
17
18export default Prueba;
uso de clases con className#
En JSX se reemplaza el atributo class por className:
1import './Prueba.css';
2
3function Prueba(){
4 const lanzamiento = 2017;
5
6 return(
7 <div>
8 {/* implementar clase: */}
9 <p className={"switch"}>Nintendo Switch</p>
10 {/* uso ternario de clases condicionales: */}
11 <p className={lanzamiento ? 'showLanzamiento' : 'hideLanzamiento'}>Lanzamiento: {lanzamiento}</p>
12 </div>
13 );
14}
15
16export default Prueba;
Recorrer array con map#
1import './Prueba.css';
2
3function Prueba(){
4 const consolas = ["Nintendo Switch", "Gameboy", "Master System", "Playstation"];
5
6 return(
7 <div>
8 {/* recorrer elementos con map (importante añadir una key): */}
9 <ol>
10 {
11 consolas.map( consola =>{
12 return <li key={consola}>{consola}</li>
13 })
14 }
15 </ol>
16 </div>
17 );
18}
19
20export default Prueba;
Recorrer array de objetos con map#
1import './Prueba.css';
2
3function Prueba(){
4 const consolas = [
5 {marca: "Nintendo", modelo: "Switch"},
6 {marca: "Sega", modelo: "Master System"},
7 {marca: "Sony", modelo: "PlayStation"}
8 ];
9
10 return(
11 consolas.map( consola =>{
12 return(
13 <div key={consola.modelo}>
14 <ul>
15 <li>{consola.marca}</li>
16 <li>{consola.modelo}</li>
17 </ul>
18 </div>
19 )
20 })
21 );
22}
23
24export default Prueba;
Nota
Hemos añadido un segundo return para poder añadir más de una línea de JSX dentro del bucle.
Nota
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#
1import {Fragment} from 'react';
2import './App.css';
3
4function App() {
5// función que dispara el evento:
6const mensaje = (e) => {
7 // lanzar mensaje con alguna propiedad del botón:
8 alert(`se ha pulsado ${e.target.innerText}`);
9}
10
11return (
12 <Fragment>
13 {/* botón con el evento click: */}
14 <button onClick={mensaje}>Disparar mensaje de alerta</button>
15 </Fragment>
16);
17}
18
19export default App;
Eventos con retorno y parámetros#
1import {Fragment} from 'react';
2import './App.css';
3
4function App() {
5// se recibén en el callback los parámetros:
6const consola = (marca, modelo) => {
7 // los eventos que retornan algo también reciben algo:
8 return (e) => {
9 // 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:
10
11 // parametros recibidos:
12 alert(`${marca} ${modelo}`);
13 // evento recibido por return:
14 alert(`se ha pulsado ${e.target.innerText}`);
15
16 }
17}
18
19return (
20 <Fragment>
21 {/* el evento recibe la función con los parámetros:: */}
22 <button onClick={consola('Nintendo','Switch')}>Averiguar videoconsola</button>
23 </Fragment>
24);
25}
26
27export 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:
1import {Fragment} from 'react';
2// importar el hook:
3import {useState} from 'react';
4import './App.css';
5
6function App() {
7// el elemento consola será un hook con un valor por defecto:
8const [consola, setConsola] = useState("ej. Gameboy");
9
10// a continuación se usará una función que ejecute el cambio de estado:
11const consolaChange = (e) => {
12 // recuperar el valor del input:
13 setConsola(e.target.value);
14}
15
16return (
17 <Fragment>
18 <h1>¿Cuál es tu videoconsola favorita?</h1>
19 <input type="text" onChange={consolaChange} />
20 <p>Mi videoconsola favorita es: {consola}</p>
21 </Fragment>
22);
23}
24
25export default App;
useEffect#
Realiza la ejecución de código después de renderizar la pantalla. Muy útil para subscribirse a servicios rest:
1// se importa useEffect:
2import {useState, useEffect} from 'react';
3
4function App() {
5 // se declara el hook tipo useState:
6 const [mensaje, setMensaje] = useState(0);
7
8 // el código de useEffect se ejecuta una vez renderizado el componente:
9 useEffect(
10 () => {
11 // modificación de estado:
12 window.setTimeout(()=>{
13 setMensaje(mensaje + 1);
14 }, 1000);
15 }, [mensaje] // este valor se dispara cuando detecta un cambio de estado
16 )
17
18 return <p>{mensaje}</p>;
19}
20
21export default App;
useContext#
Crea un contexto por el que se pueden enviar propiedades a cualquier componente sin tener que enviarlo por parámetros:
Archivo que recibe el contexto message.js:
1// importar en el archivo React y el hook:
2import React, {useContext} from 'react';
3// crear un mensaje:
4const mensaje = "Mensaje genérico";
5// cargar en el contexto de React:
6const MensajeContext = React.createContext(mensaje);
Uso del contexto:
1function App() {
2// utilizar el context sin necesidad de hacer nada mas:
3const mensaje = useContext(MensajeContext);
4return <p>{mensaje}</p>;
5}
6
7export default App;
Formularios en React#
Combinando el uso de eventos y hooks se preparan los formularios
1import {Fragment} from 'react';
2// importar el hook:
3import {useState} from 'react';
4import './App.css';
5
6function App() {
7// crear los hooks para el usuario y contraseña:
8const [usuario, setUsuario] = useState('');
9const [password, setPassword] = useState('');
10
11// cuando escribimos en el campo se irá cambiando su estado:
12const handleUsuario = (evento) =>{
13 // se recupera el evento:
14 setUsuario(evento.target.value);
15 console.log(evento.target.value);
16}
17
18const handlePassword = (evento) =>{
19 // se recupera el evento:
20 setPassword(evento.target.value);
21}
22
23// Ejecutamos esta acción al hacer login:
24const login = (e) =>{
25 // para prevenir que refresque por defecto la página:
26 e.preventDefault();
27 if(usuario === 'guillermo' && password === "1234"){
28 alert("Sesión iniciada correctamente");
29 }else{
30 alert("Error al iniciar sesión");
31 }
32}
33
34return (
35 <>
36 <form onSubmit={login}>
37 <input type="text" placeholder="Usuario" onChange={handleUsuario} />
38 <input type="password" placeholder="Contraseña" onChange={handlePassword} />
39 <input type="submit" value="Iniciar sesión" />
40 </form>
41 </>
42);
43}
44
45export 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#
Dentro de la carpeta src crear archivo Router.js:
1// importar funciones del modulo react router:
2import {BrowserRouter, Route, Routes} from 'react-router-dom';
3// importar fragment también:
4import {Fragment} from 'react';
5
6// importar los componentes de vista:
7import Inicio from './Inicio';
8import Prueba from './Prueba';
9import Error from './Error';
10import Parametros from './Parametros';
11
12function Router(){
13 // retornar la estructura de rutas:
14 return(
15 <Fragment>
16 <BrowserRouter>
17 <Routes>
18 {/* Ruta raiz (necesita el atributo exact): */}
19 <Route exact path="/" element={<Inicio />} />
20 <Route path="/prueba" element={<Prueba />} />
21 {/* Ruta con parametros: */}
22 <Route path="/parametros/:nombre" element={<Parametros />} />
23 {/* Ruta para urls no establecidas (error 404): */}
24 <Route path="*" element={<Error />} />
25 </Routes>
26 </BrowserRouter>
27 </Fragment>
28 )
29}
30
31export default Router;
Cargar el enrutador en App.js:
1import {Fragment} from 'react';
2import './App.css';
3// importar router:
4import Router from './Router';
5
6function App() {
7// cargar directamente el router en el return:
8return(
9 <Fragment>
10 <Router />
11 </Fragment>
12)
13
14}
15
16export default App;
Recibir parámetros de una ruta#
Recibir parametros en el controlador Parametros.js:
1// importar useParams de React Router:
2import { useParams } from 'react-router-dom';
3
4function Parametros(){
5 // cargar un parametro mediante desestructuración:
6 const {nombre} = useParams();
7
8 return(
9 <div>
10 <h1>Te llamas: {nombre}</h1>
11 </div>
12 )
13}
14
15export default Parametros;