diff --git a/_quarto.yml b/_quarto.yml index fa4635b..d021f59 100644 --- a/_quarto.yml +++ b/_quarto.yml @@ -75,6 +75,11 @@ website: contents: - pages/Bloque3/Intermedio.qmd - pages/Bloque3/MARef.qmd + + - section: "Semana 10" + contents: + - pages/Bloque3/ReactIV.qmd + - text: "Próximamente..." diff --git a/docs/about.pdf b/docs/about.pdf index fe9334c..5944956 100644 Binary files a/docs/about.pdf and b/docs/about.pdf differ diff --git a/docs/index.html b/docs/index.html index ad6869c..45b4d74 100644 --- a/docs/index.html +++ b/docs/index.html @@ -503,6 +503,23 @@ MA: Uncontrolled fields y useRef + + + + diff --git a/docs/index.pdf b/docs/index.pdf index 038dc75..ae94c8c 100644 Binary files a/docs/index.pdf and b/docs/index.pdf differ diff --git a/docs/pages/Bloque1/MAcss.html b/docs/pages/Bloque1/MAcss.html index e806338..937eb8d 100644 --- a/docs/pages/Bloque1/MAcss.html +++ b/docs/pages/Bloque1/MAcss.html @@ -504,6 +504,23 @@ MA: Uncontrolled fields y useRef + + + + diff --git a/docs/pages/Bloque1/MAcss.pdf b/docs/pages/Bloque1/MAcss.pdf index db7d416..bdb3f0a 100644 Binary files a/docs/pages/Bloque1/MAcss.pdf and b/docs/pages/Bloque1/MAcss.pdf differ diff --git a/docs/pages/Bloque1/MAhtml2.html b/docs/pages/Bloque1/MAhtml2.html index 6fe7809..3f42d56 100644 --- a/docs/pages/Bloque1/MAhtml2.html +++ b/docs/pages/Bloque1/MAhtml2.html @@ -504,6 +504,23 @@ MA: Uncontrolled fields y useRef + + + + diff --git a/docs/pages/Bloque1/MAhtml2.pdf b/docs/pages/Bloque1/MAhtml2.pdf index 1200a72..3b047e7 100644 Binary files a/docs/pages/Bloque1/MAhtml2.pdf and b/docs/pages/Bloque1/MAhtml2.pdf differ diff --git a/docs/pages/Bloque1/bloque1.html b/docs/pages/Bloque1/bloque1.html index 74040b5..460f62c 100644 --- a/docs/pages/Bloque1/bloque1.html +++ b/docs/pages/Bloque1/bloque1.html @@ -504,6 +504,23 @@ MA: Uncontrolled fields y useRef + + + + diff --git a/docs/pages/Bloque1/bloque1.pdf b/docs/pages/Bloque1/bloque1.pdf index 6f8c0bd..12e1d01 100644 Binary files a/docs/pages/Bloque1/bloque1.pdf and b/docs/pages/Bloque1/bloque1.pdf differ diff --git a/docs/pages/Bloque1/css.html b/docs/pages/Bloque1/css.html index c5ae889..21430c6 100644 --- a/docs/pages/Bloque1/css.html +++ b/docs/pages/Bloque1/css.html @@ -539,6 +539,23 @@ MA: Uncontrolled fields y useRef + + + + diff --git a/docs/pages/Bloque1/css.pdf b/docs/pages/Bloque1/css.pdf index c50b9d9..c994227 100644 Binary files a/docs/pages/Bloque1/css.pdf and b/docs/pages/Bloque1/css.pdf differ diff --git a/docs/pages/Bloque1/entorno.html b/docs/pages/Bloque1/entorno.html index 78cdec5..6dc773a 100644 --- a/docs/pages/Bloque1/entorno.html +++ b/docs/pages/Bloque1/entorno.html @@ -504,6 +504,23 @@ MA: Uncontrolled fields y useRef + + + + diff --git a/docs/pages/Bloque1/entorno.pdf b/docs/pages/Bloque1/entorno.pdf index 9a62ade..945c17d 100644 Binary files a/docs/pages/Bloque1/entorno.pdf and b/docs/pages/Bloque1/entorno.pdf differ diff --git a/docs/pages/Bloque1/html.html b/docs/pages/Bloque1/html.html index b4caa4c..667a704 100644 --- a/docs/pages/Bloque1/html.html +++ b/docs/pages/Bloque1/html.html @@ -539,6 +539,23 @@ MA: Uncontrolled fields y useRef + + + + diff --git a/docs/pages/Bloque1/html.pdf b/docs/pages/Bloque1/html.pdf index 10ece12..a818bca 100644 Binary files a/docs/pages/Bloque1/html.pdf and b/docs/pages/Bloque1/html.pdf differ diff --git a/docs/pages/Bloque1/t1.html b/docs/pages/Bloque1/t1.html index 5389a96..3b7591b 100644 --- a/docs/pages/Bloque1/t1.html +++ b/docs/pages/Bloque1/t1.html @@ -539,6 +539,23 @@ MA: Uncontrolled fields y useRef + + + + diff --git a/docs/pages/Bloque1/t1.pdf b/docs/pages/Bloque1/t1.pdf index 67a7e71..486e387 100644 Binary files a/docs/pages/Bloque1/t1.pdf and b/docs/pages/Bloque1/t1.pdf differ diff --git a/docs/pages/Bloque1/t1a.html b/docs/pages/Bloque1/t1a.html index e667795..78003fd 100644 --- a/docs/pages/Bloque1/t1a.html +++ b/docs/pages/Bloque1/t1a.html @@ -504,6 +504,23 @@ MA: Uncontrolled fields y useRef + + + + diff --git a/docs/pages/Bloque1/t1a.pdf b/docs/pages/Bloque1/t1a.pdf index 8a109c1..9b07f21 100644 Binary files a/docs/pages/Bloque1/t1a.pdf and b/docs/pages/Bloque1/t1a.pdf differ diff --git a/docs/pages/Bloque1/t2.html b/docs/pages/Bloque1/t2.html index 558fae6..c06b7d5 100644 --- a/docs/pages/Bloque1/t2.html +++ b/docs/pages/Bloque1/t2.html @@ -504,6 +504,23 @@ MA: Uncontrolled fields y useRef + + + + diff --git a/docs/pages/Bloque1/t2.pdf b/docs/pages/Bloque1/t2.pdf index f8f2f58..1984a12 100644 Binary files a/docs/pages/Bloque1/t2.pdf and b/docs/pages/Bloque1/t2.pdf differ diff --git a/docs/pages/Bloque1/t2a.html b/docs/pages/Bloque1/t2a.html index 7e058ee..85ad2f8 100644 --- a/docs/pages/Bloque1/t2a.html +++ b/docs/pages/Bloque1/t2a.html @@ -504,6 +504,23 @@ MA: Uncontrolled fields y useRef + + + + diff --git a/docs/pages/Bloque1/t2a.pdf b/docs/pages/Bloque1/t2a.pdf index 0fee716..ca7db80 100644 Binary files a/docs/pages/Bloque1/t2a.pdf and b/docs/pages/Bloque1/t2a.pdf differ diff --git a/docs/pages/Bloque2/MAclases.html b/docs/pages/Bloque2/MAclases.html index 61c3628..d72a4f4 100644 --- a/docs/pages/Bloque2/MAclases.html +++ b/docs/pages/Bloque2/MAclases.html @@ -539,6 +539,23 @@ MA: Uncontrolled fields y useRef + + + + diff --git a/docs/pages/Bloque2/MAclases.pdf b/docs/pages/Bloque2/MAclases.pdf index 1c2e894..7354f3e 100644 Binary files a/docs/pages/Bloque2/MAclases.pdf and b/docs/pages/Bloque2/MAclases.pdf differ diff --git a/docs/pages/Bloque2/intensivo.html b/docs/pages/Bloque2/intensivo.html index 4859f52..3fb3330 100644 --- a/docs/pages/Bloque2/intensivo.html +++ b/docs/pages/Bloque2/intensivo.html @@ -539,6 +539,23 @@ MA: Uncontrolled fields y useRef + + + + diff --git a/docs/pages/Bloque2/intensivo.pdf b/docs/pages/Bloque2/intensivo.pdf index dfa7901..7882c9d 100644 Binary files a/docs/pages/Bloque2/intensivo.pdf and b/docs/pages/Bloque2/intensivo.pdf differ diff --git a/docs/pages/Bloque2/jsI.pdf b/docs/pages/Bloque2/jsI.pdf index a86934c..13a486c 100644 Binary files a/docs/pages/Bloque2/jsI.pdf and b/docs/pages/Bloque2/jsI.pdf differ diff --git a/docs/pages/Bloque2/ti.html b/docs/pages/Bloque2/ti.html index ab80537..36580c5 100644 --- a/docs/pages/Bloque2/ti.html +++ b/docs/pages/Bloque2/ti.html @@ -504,6 +504,23 @@ MA: Uncontrolled fields y useRef + + + + diff --git a/docs/pages/Bloque2/ti.pdf b/docs/pages/Bloque2/ti.pdf index 505ca1a..0596bd0 100644 Binary files a/docs/pages/Bloque2/ti.pdf and b/docs/pages/Bloque2/ti.pdf differ diff --git a/docs/pages/Bloque2/tia.html b/docs/pages/Bloque2/tia.html index 3b6088e..0297cb3 100644 --- a/docs/pages/Bloque2/tia.html +++ b/docs/pages/Bloque2/tia.html @@ -539,6 +539,23 @@ MA: Uncontrolled fields y useRef + + + + diff --git a/docs/pages/Bloque2/tia.pdf b/docs/pages/Bloque2/tia.pdf index 5386b5f..385bb03 100644 Binary files a/docs/pages/Bloque2/tia.pdf and b/docs/pages/Bloque2/tia.pdf differ diff --git a/docs/pages/Bloque3/DOM.html b/docs/pages/Bloque3/DOM.html index 1d8da61..b038b42 100644 --- a/docs/pages/Bloque3/DOM.html +++ b/docs/pages/Bloque3/DOM.html @@ -539,6 +539,23 @@ MA: Uncontrolled fields y useRef + + + + diff --git a/docs/pages/Bloque3/DOM.pdf b/docs/pages/Bloque3/DOM.pdf index ed37bbc..92be53e 100644 Binary files a/docs/pages/Bloque3/DOM.pdf and b/docs/pages/Bloque3/DOM.pdf differ diff --git a/docs/pages/Bloque3/Intermedio.html b/docs/pages/Bloque3/Intermedio.html index 05063ba..cc0431a 100644 --- a/docs/pages/Bloque3/Intermedio.html +++ b/docs/pages/Bloque3/Intermedio.html @@ -539,6 +539,23 @@ MA: Uncontrolled fields y useRef + + + + diff --git a/docs/pages/Bloque3/Intermedio.pdf b/docs/pages/Bloque3/Intermedio.pdf index 0e6a7f1..b5b5d3b 100644 Binary files a/docs/pages/Bloque3/Intermedio.pdf and b/docs/pages/Bloque3/Intermedio.pdf differ diff --git a/docs/pages/Bloque3/MARef.html b/docs/pages/Bloque3/MARef.html index aa506de..357c3d9 100644 --- a/docs/pages/Bloque3/MARef.html +++ b/docs/pages/Bloque3/MARef.html @@ -504,6 +504,23 @@ MA: Uncontrolled fields y useRef + + + + diff --git a/docs/pages/Bloque3/MARef.pdf b/docs/pages/Bloque3/MARef.pdf index 7c98c9d..252ceef 100644 Binary files a/docs/pages/Bloque3/MARef.pdf and b/docs/pages/Bloque3/MARef.pdf differ diff --git a/docs/pages/Bloque3/MAcss2.html b/docs/pages/Bloque3/MAcss2.html index 0d19686..ef72ee6 100644 --- a/docs/pages/Bloque3/MAcss2.html +++ b/docs/pages/Bloque3/MAcss2.html @@ -504,6 +504,23 @@ MA: Uncontrolled fields y useRef + + + + diff --git a/docs/pages/Bloque3/MAcss2.pdf b/docs/pages/Bloque3/MAcss2.pdf index 785ce72..d8fe918 100644 Binary files a/docs/pages/Bloque3/MAcss2.pdf and b/docs/pages/Bloque3/MAcss2.pdf differ diff --git a/docs/pages/Bloque3/ReactI.html b/docs/pages/Bloque3/ReactI.html index 3ed455c..d422eb9 100644 --- a/docs/pages/Bloque3/ReactI.html +++ b/docs/pages/Bloque3/ReactI.html @@ -539,6 +539,23 @@ MA: Uncontrolled fields y useRef + + + + diff --git a/docs/pages/Bloque3/ReactI.pdf b/docs/pages/Bloque3/ReactI.pdf index 2058a9c..4b7a5c1 100644 Binary files a/docs/pages/Bloque3/ReactI.pdf and b/docs/pages/Bloque3/ReactI.pdf differ diff --git a/docs/pages/Bloque3/ReactIV.html b/docs/pages/Bloque3/ReactIV.html new file mode 100644 index 0000000..42a9b4c --- /dev/null +++ b/docs/pages/Bloque3/ReactIV.html @@ -0,0 +1,1315 @@ + + + + + + + + + + +React IV – Training Center SW + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ + +
+
+

React IV

+

Ecosistema npm, React Router, useContext

+
+ + + +
+ +
+
Autor/a
+
+

Javier Ribal del Río

+
+
+ +
+
Fecha de publicación
+
+

6 de marzo de 2026

+
+
+ +
+
Fecha de última modificación
+
+

4 de marzo de 2026

+
+
+ +
+ + + +
+ + +

Contenido

+ +
+

Ecosistema Node

+

Hasta ahora hemos trabajado únicamente con React y JavaScript.

+

Sin embargo, en el desarrollo real de aplicaciones es muy común utilizar librerías externas, para ello podemos recurrir Node.JS.

+

React está diseñado para funcionar dentro de un ecosistema de paquetes.

+

Ejemplos habituales:

+
    +
  • React Router → navegación
  • +
  • Axios → peticiones HTTP
  • +
  • Chart.js → gráficas
  • +
  • Zustand / Redux → gestión de estado
  • +
  • Librerías de UI: Tailwind, Bootstrap, Booswatch
  • +
+
+
+

npm

+

npm (Node Package Manager) es el sistema que permite instalar y gestionar librerías de JavaScript. Como su nombre indica, está desarrollado por Node.JS

+

Cada proyecto tiene un archivo:

+
package.json
+

En este archivo se registran las dependencias del proyecto.

+

Ejemplo:

+
{
+  "dependencies": {
+    "react": "^18.0.0",
+    "react-router-dom": "^6.0.0"
+  }
+}
+
+

Instalación de paquetes

+

Las librerías se instalan desde la terminal.

+
npm install react-router-dom
+

Esto hace tres cosas:

+
    +
  1. Descarga el paquete
  2. +
  3. Lo guarda en node_modules (capreta donde se guardan las librerías externas)
  4. +
  5. Añade la dependencia en package.json
  6. +
+
+
+
+

React Router

+

En una aplicación web tradicional cada enlace carga una página nueva.

+

En React normalmente trabajamos con Single Page Applications (SPA).

+

En una SPA:

+
    +
  • el navegador no recarga la página
  • +
  • React cambia los componentes que se muestran
  • +
+

Para gestionar esto utilizamos React Router.

+

Realmente es la misma página, solo que el usuario lo percibe como distintas páginas

+

El usuario percibirá que el sitio web está divido en diferentes subpáginas

+
    +
  • /
  • +
  • pokemons
  • +
  • pokemons/pikachu
  • +
+
+

Componentes principales de React Router

+

Los elementos fundamentales son:

+
    +
  • BrowserRouter
  • +
  • Routes
  • +
  • Route
  • +
  • Link
  • +
+

Ejemplo básico:

+
import { BrowserRouter, Routes, Route } from "react-router-dom";
+
+function App() {
+  return (
+    <BrowserRouter>
+
+      <Routes>
+
+        <Route path="/" element={<Home />} />
+
+        <Route path="/pokemons" element={<PokemonList />} />
+
+      </Routes>
+
+    </BrowserRouter>
+  );
+}
+

Elementos del código

+
    +
  • BrowserRouter
    +Es el componente que activa el sistema de navegación de React Router. Utiliza la API de historial del navegador para cambiar la URL sin recargar la página.
  • +
  • Routes
    +Es el contenedor donde se definen todas las rutas de la aplicación. React Router examina las rutas dentro de este componente para decidir qué componente mostrar.
  • +
  • Route
    +Define una ruta concreta de la aplicación.
  • +
+
    +
  • path
    +Indica la URL que activa la ruta.
    +Ejemplo: / corresponde a la página principal.
  • +
  • element
    +Es el componente de React que se renderiza cuando la URL coincide con el path.
  • +
  • <Home />
    +Componente que se muestra cuando el usuario accede a la ruta /.
  • +
  • <PokemonList />
    +Componente que se muestra cuando el usuario accede a la ruta /pokemons.
  • +
+
+ +
+

Parámetros dinámicos

+

Podemos crear rutas dinámicas.

+

Ejemplo:

+
/pokemon/25
+/pokemon/7
+

Definición de la ruta:

+
<Route path="/pokemon/:id" element={<PokemonDetail />} />
+
+

useParams

+

Para acceder al parámetro utilizamos el hook useParams de React Router.

+
import { useParams } from "react-router-dom";
+
+function PokemonDetail() {
+
+  const { id } = useParams();
+
+  return <p>Pokemon {id}</p>;
+
+}
+

Este parámetro puede utilizarse para realizar peticiones a una API.

+
+
+
+
+

Context API

+

En aplicaciones grandes aparece un problema frecuente.

+

Muchos componentes necesitan acceder a la misma información.

+

Por ejemplo:

+
    +
  • usuario
  • +
  • tema visual
  • +
  • idioma
  • +
  • configuración
  • +
+

Si pasamos la información mediante props, los datos deben atravesar muchos componentes.

+

Representación conceptual:

+
App
+ └ Layout
+    └ Page
+       └ Component
+

Si todos necesitan user, debemos pasar la prop continuamente.

+

Este problema se conoce como prop drilling.

+
+

Context

+

React proporciona una solución llamada Context.

+

Context permite compartir información entre múltiples componentes sin pasar props manualmente.

+

El proceso tiene tres pasos:

+
    +
  1. Crear el contexto
  2. +
  3. Proveer el contexto
  4. +
  5. Consumir el contexto
  6. +
+
+

Crear un contexto

+
import { createContext } from "react";
+
+const UserContext = createContext();
+

Esto crea un contenedor que puede almacenar información compartida.

+
+
+

Provider

+

El Provider permite que los componentes hijos accedan al contexto.

+
<UserContext.Provider value={user}>
+
+  <App />
+
+</UserContext.Provider>
+

Todos los componentes dentro del Provider pueden acceder al valor.

+
+
+

Consumir el contexto

+

Para acceder al contexto utilizamos el hook useContext.

+
import { useContext } from "react";
+
+const user = useContext(UserContext);
+

El componente obtiene directamente el valor almacenado en el contexto.

+
+
+

Ejemplo completo

+
import { createContext, useContext } from "react";
+
+const UserContext = createContext();
+
+function App() {
+
+  const user = { name: "Javier" };
+
+  return (
+
+    <UserContext.Provider value={user}>
+
+      <Profile />
+
+    </UserContext.Provider>
+
+  );
+}
+
+function Profile() {
+
+  const user = useContext(UserContext);
+
+  return <h1>{user.name}</h1>;
+
+}
+ + +
+
+
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/docs/pages/Bloque3/ReactIV.pdf b/docs/pages/Bloque3/ReactIV.pdf new file mode 100644 index 0000000..29a05a9 Binary files /dev/null and b/docs/pages/Bloque3/ReactIV.pdf differ diff --git a/docs/pages/Bloque3/presentacion-reactIV.html b/docs/pages/Bloque3/presentacion-reactIV.html new file mode 100644 index 0000000..19b955c --- /dev/null +++ b/docs/pages/Bloque3/presentacion-reactIV.html @@ -0,0 +1,879 @@ + + + + + + + + + + + + + + Training Center SW – React IV + + + + + + + + + + + + + + + + +
+
+ +
+

React IV

+

Ecosistema npm, React Router, useContext

+ +
+
+
+Javier Ribal del Río +
+
+
+ +

2026-03-06

+
+
+ +

Contenido

+
    +
  • Ecosistema React y paquetes npm
  • +
  • Librerías externas
  • +
  • React Router
  • +
  • Parámetros de URL
  • +
  • useContext
  • +
+
+
+

Ecosistema Node

+

Hasta ahora hemos trabajado únicamente con React y JavaScript.

+

Sin embargo, en el desarrollo real de aplicaciones es muy común utilizar librerías externas, para ello podemos recurrir Node.JS.

+

React está diseñado para funcionar dentro de un ecosistema de paquetes.

+
+
+ +

Ejemplos habituales:

+
    +
  • React Router → navegación
  • +
  • Axios → peticiones HTTP
  • +
  • Chart.js → gráficas
  • +
  • Zustand / Redux → gestión de estado
  • +
  • Librerías de UI: Tailwind, Bootstrap, Booswatch
  • +
+
+
+

npm

+

npm (Node Package Manager) es el sistema que permite instalar y gestionar librerías de JavaScript. Como su nombre indica, está desarrollado por Node.JS

+

Cada proyecto tiene un archivo:

+
package.json
+

En este archivo se registran las dependencias del proyecto.

+
+
+ +

Ejemplo:

+
{
+  "dependencies": {
+    "react": "^18.0.0",
+    "react-router-dom": "^6.0.0"
+  }
+}
+
+
+ +

Instalación de paquetes

+

Las librerías se instalan desde la terminal.

+
npm install react-router-dom
+

Esto hace tres cosas:

+
    +
  1. Descarga el paquete
  2. +
  3. Lo guarda en node_modules (capreta donde se guardan las librerías externas)
  4. +
  5. Añade la dependencia en package.json
  6. +
+
+
+

React Router

+

En una aplicación web tradicional cada enlace carga una página nueva.

+

En React normalmente trabajamos con Single Page Applications (SPA).

+

En una SPA:

+
    +
  • el navegador no recarga la página
  • +
  • React cambia los componentes que se muestran
  • +
+

Para gestionar esto utilizamos React Router.

+

Realmente es la misma página, solo que el usuario lo percibe como distintas páginas

+
+
+ +

El usuario percibirá que el sitio web está divido en diferentes subpáginas

+
    +
  • /
  • +
  • pokemons
  • +
  • pokemons/pikachu
  • +
+
+
+ +

Componentes principales de React Router

+

Los elementos fundamentales son:

+
    +
  • BrowserRouter
  • +
  • Routes
  • +
  • Route
  • +
  • Link
  • +
+

Ejemplo básico:

+
+
+ +
import { BrowserRouter, Routes, Route } from "react-router-dom";
+
+function App() {
+  return (
+    <BrowserRouter>
+
+      <Routes>
+
+        <Route path="/" element={<Home />} />
+
+        <Route path="/pokemons" element={<PokemonList />} />
+
+      </Routes>
+
+    </BrowserRouter>
+  );
+}
+
+
+ +

Elementos del código

+
    +
  • BrowserRouter
    +Es el componente que activa el sistema de navegación de React Router. Utiliza la API de historial del navegador para cambiar la URL sin recargar la página.
  • +
  • Routes
    +Es el contenedor donde se definen todas las rutas de la aplicación. React Router examina las rutas dentro de este componente para decidir qué componente mostrar.
  • +
  • Route
    +Define una ruta concreta de la aplicación.
  • +
+
+
+ +
    +
  • path
    +Indica la URL que activa la ruta.
    +Ejemplo: / corresponde a la página principal.
  • +
  • element
    +Es el componente de React que se renderiza cuando la URL coincide con el path.
  • +
  • <Home />
    +Componente que se muestra cuando el usuario accede a la ruta /.
  • +
  • <PokemonList />
    +Componente que se muestra cuando el usuario accede a la ruta /pokemons.
  • +
+
+
+ + +

Para navegar entre páginas utilizamos el componente Link.

+
import { Link } from "react-router-dom";
+
+<Link to="/">Inicio</Link>
+
+<Link to="/pokemon">Pokemon</Link>
+

A diferencia de <a>:

+
    +
  • no recarga la página
  • +
  • React cambia el componente visible
  • +
+
+
+ +

Parámetros dinámicos

+

Podemos crear rutas dinámicas.

+

Ejemplo:

+
/pokemon/25
+/pokemon/7
+

Definición de la ruta:

+
<Route path="/pokemon/:id" element={<PokemonDetail />} />
+
+
+ +

useParams

+

Para acceder al parámetro utilizamos el hook useParams de React Router.

+
import { useParams } from "react-router-dom";
+
+function PokemonDetail() {
+
+  const { id } = useParams();
+
+  return <p>Pokemon {id}</p>;
+
+}
+

Este parámetro puede utilizarse para realizar peticiones a una API.

+
+
+

Context API

+

En aplicaciones grandes aparece un problema frecuente.

+

Muchos componentes necesitan acceder a la misma información.

+

Por ejemplo:

+
    +
  • usuario
  • +
  • tema visual
  • +
  • idioma
  • +
  • configuración
  • +
+

Si pasamos la información mediante props, los datos deben atravesar muchos componentes.

+
+
+ +

Representación conceptual:

+
App
+ └ Layout
+    └ Page
+       └ Component
+

Si todos necesitan user, debemos pasar la prop continuamente.

+

Este problema se conoce como prop drilling.

+
+
+ +

Context

+

React proporciona una solución llamada Context.

+

Context permite compartir información entre múltiples componentes sin pasar props manualmente.

+

El proceso tiene tres pasos:

+
    +
  1. Crear el contexto
  2. +
  3. Proveer el contexto
  4. +
  5. Consumir el contexto
  6. +
+
+
+ +

Crear un contexto

+
import { createContext } from "react";
+
+const UserContext = createContext();
+

Esto crea un contenedor que puede almacenar información compartida.

+
+
+ +

Provider

+

El Provider permite que los componentes hijos accedan al contexto.

+
<UserContext.Provider value={user}>
+
+  <App />
+
+</UserContext.Provider>
+

Todos los componentes dentro del Provider pueden acceder al valor.

+
+
+ +

Consumir el contexto

+

Para acceder al contexto utilizamos el hook useContext.

+
import { useContext } from "react";
+
+const user = useContext(UserContext);
+

El componente obtiene directamente el valor almacenado en el contexto.

+
+
+ +

Ejemplo completo

+
import { createContext, useContext } from "react";
+
+const UserContext = createContext();
+
+function App() {
+
+  const user = { name: "Javier" };
+
+  return (
+
+    <UserContext.Provider value={user}>
+
+      <Profile />
+
+    </UserContext.Provider>
+
+  );
+}
+
+function Profile() {
+
+  const user = useContext(UserContext);
+
+  return <h1>{user.name}</h1>;
+
+}
+
+
+ + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/pages/Bloque3/ps.html b/docs/pages/Bloque3/ps.html index 1d06ecc..208b93d 100644 --- a/docs/pages/Bloque3/ps.html +++ b/docs/pages/Bloque3/ps.html @@ -504,6 +504,23 @@ MA: Uncontrolled fields y useRef + + + + diff --git a/docs/pages/Bloque3/ps.pdf b/docs/pages/Bloque3/ps.pdf index 799b0d6..b939cfc 100644 Binary files a/docs/pages/Bloque3/ps.pdf and b/docs/pages/Bloque3/ps.pdf differ diff --git a/docs/pages/Bloque3/t6.html b/docs/pages/Bloque3/t6.html index 39b83ab..14d9139 100644 --- a/docs/pages/Bloque3/t6.html +++ b/docs/pages/Bloque3/t6.html @@ -539,6 +539,23 @@ MA: Uncontrolled fields y useRef + + + + diff --git a/docs/pages/Bloque3/t6.pdf b/docs/pages/Bloque3/t6.pdf index 95dd72b..11027cf 100644 Binary files a/docs/pages/Bloque3/t6.pdf and b/docs/pages/Bloque3/t6.pdf differ diff --git a/docs/pages/Bloque3/t9.html b/docs/pages/Bloque3/t9.html new file mode 100644 index 0000000..e6fa209 --- /dev/null +++ b/docs/pages/Bloque3/t9.html @@ -0,0 +1,973 @@ + + + + + + + + + + +T6: Romancero Gitano I – Training Center SW + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+
+

T6: Romancero Gitano I

+
+ + + +
+ +
+
Autor/a
+
+

Javier Ribal del Río

+
+
+ +
+
Fecha de publicación
+
+

19 de diciembre de 2025

+
+
+ +
+
Fecha de última modificación
+
+

4 de marzo de 2026

+
+
+ +
+ + + +
+ + +
+

Objetivo de la tarea

+

El objetivo de esta tarea es aplicar los conceptos básicos de HTML, CSS y JavaScript (DOM) para crear una página web interactiva que muestre poemas del Romancero gitano de Federico García Lorca y modifique su apariencia visual en función de las diferentes metáforas.

+

Resultado esperado

+
+
+

Estructura HTML

+

El documento HTML debe:

+
    +
  • Estar correctamente estructurado (<!DOCTYPE>, <html>, <head>, <body>).
  • +
  • Contener un contenedor principal centrado horizontalmente.
  • +
  • Incluir, en este orden: +
      +
    1. Un elemento para mostrar información métrica del poema (número de estrofas y versos).
    2. +
    3. Un elemento para el título del poema.
    4. +
    5. Un elemento para el texto del poema, respetando los saltos de verso utilizando la etiqueta <pre>.
    6. +
    7. Un botón que permita cambiar de poema.
    8. +
  • +
+

No debe utilizarse ningún framework ni librería externa.

+
+
+

JavaScript

+
+

Datos

+

En JavaScript se debe definir un array de objetos, donde cada objeto represente un poema y tenga al menos:

+
    +
  • Un título.
  • +
  • El texto del poema como una cadena de texto, usando saltos de línea para los versos.
  • +
+

El cambio de poema debe hacerse recorriendo este array de forma cíclica (cola circular) mediante el botón.

+

Descargar poemas (click derecho guardar enlace como)

+
+
+

Manipulación del DOM

+

El comportamiento de la página debe implementarse exclusivamente con DOM nativo, cumpliendo lo siguiente:

+
    +
  • Todas las funciones deben declararse como arrow functions.
  • +
  • Al pulsar el botón: +
      +
    • Se actualiza el título.
    • +
    • Se actualiza el texto del poema.
    • +
    • Se modifica el formato del fondo.
    • +
    • Se recalculan y muestran: +
        +
      • Número de versos.
      • +
      • Número de estrofas (bloques separados por líneas en blanco).
      • +
    • +
  • +
+

El cálculo debe realizarse a partir del texto del poema, no con valores predefinidos.

+
+
+
+

CSS

+

Lorca utiliza las metáforas y la alegoría como elemento principal sobre el que construye sus poemas, al analizar profundamente descubrimos que siempre recurre a las mismas metáforas.

+

El color no se utiliza aquí solo como elemento decorativo, sino como un recurso semántico: cada color representa un símbolo literario presente en el poema.

+

Desde el punto de vista técnico: - Los colores de fondo y de texto deben definirse en clases CSS. - JavaScript no decide colores, únicamente decide qué clase aplicar según el contenido del poema.

+
+

Palabras clave y colores asociados

+

Se debe detectar el texto del poema las siguientes palabras clave y aplicar el color de fondo correspondiente:

+
    +
  • guardia civil → fondo verde militar
  • +
  • sangre → fondo granate oscuro
  • +
  • caballo → fondo color tierra
  • +
  • cuchillo / navaja → fondo plateado
  • +
+

El color del texto debe elegirse siempre de forma que exista contraste suficiente con el fondo y se garantice la legibilidad.

+

Si el poema contiene varias palabras clave, solo debe aplicarse un único estilo, siguiendo un orden de prioridad definido previamente.

+

Si el poema no contiene ninguna de estas palabras, se aplicará un estilo por defecto con colores aleatorios.

+
+
+
+

Extra opcional: símbolo aurora 🌈

+

De forma voluntaria, se puede añadir el símbolo aurora, que tendrá prioridad absoluta sobre todos los demás.

+

Cuando el poema contenga la palabra aurora, el fondo debe mostrar un degradado animado.

+
+

CSS necesario para el extra

+
.aurora {
+  background: linear-gradient(120deg,
+    #ff005d,
+    #ff9f1c,
+    #ffee32,
+    #3cff00,
+    #00e5ff,
+    #7a00ff,
+    #ff00c8
+  );
+  background-size: 600% 600%;
+  animation: aurora 10s linear infinite;
+  color: black;
+}
+
+@keyframes aurora {
+  0%   { background-position: 0% 50%; }
+  50%  { background-position: 100% 50%; }
+  100% { background-position: 0% 50%; }
+}
+
+
+
+
+

Consejos

+
+

Centrado de la página (layout clásico)

+

Toda la página debe estar centrada horizontalmente.

+

El centrado se consigue mediante:

+
    +
  • Un contenedor con un ancho máximo definido.
  • +
  • Márgenes automáticos a izquierda y derecha.
  • +
+

Desde el punto de vista conceptual:

+
    +
  • margin: 0 auto no centra texto, centra bloques.
  • +
  • El navegador reparte automáticamente el espacio sobrante a ambos lados del contenedor.
  • +
+
+
+

Animación del cambio de color

+

Para evitar que los cambios de color sean bruscos, se utiliza la propiedad transition en CSS.

+

Esta propiedad indica al navegador que los cambios en determinadas propiedades visuales deben hacerse de forma progresiva.

+

Ejemplo conceptual:

+
body {
+  transition: background-color 0.6s, color 0.6s;
+}
+

Gracias a esta transición: - Cuando JavaScript cambia una clase o un color, - el navegador interpola automáticamente entre el color anterior y el nuevo.

+

No es necesario programar animaciones en JavaScript: CSS se encarga de todo el efecto visual.

+
+
+

Búsqueda de una palabra

+

Para buscar si determinada palabra determinada se debe utilizar la función includes de la clase string

+

+texto = "hoy nieva";
+
+texto.includes("nieva");    //TRUE
+texto.includes("llueve");   //FALSE
+
+
+

Generación del color aleatorio

+

Para la generacióndel color aleatorio de puede utilizar la siguiente función

+
const randomColor = () => '#' + Math.floor(Math.random() * 16777215).toString(16);
+
+
+

Conteo versos y estrofas

+

El recuento de versos y estrofas debe hacerse a partir del texto del poema, no con valores escritos a mano. A continuación se dan algunas pistas técnicas para abordar este problema.

+
+

Conteo de versos

+

Un verso puede considerarse, a efectos prácticos en esta tarea, como una línea de texto no vacía.

+

Una estrategia habitual consiste en: - Separar el texto por saltos de línea. - Eliminar las líneas vacías o formadas solo por espacios. - Contar cuántas líneas válidas quedan.

+

Ejemplo orientativo:

+
const versos = texto
+  .split('\n')
+  .filter(linea => linea.trim() !== '')
+  .length;
+

Este enfoque es suficiente para la mayoría de los poemas del Romancero gitano y evita errores frecuentes.

+
+
+

Conteo de estrofas

+

Una estrofa puede entenderse como un bloque de versos separado de otros bloques por una línea en blanco.

+

Una posible estrategia es: - Separar el texto usando dos (o más) saltos de línea consecutivos. - Eliminar bloques vacíos. - Contar los bloques resultantes.

+

Ejemplo orientativo:

+
const estrofas = texto
+  .split(/\n\s*\n/)
+  .filter(bloque => bloque.trim() !== '')
+  .length;
+

Entrega: un único archivo HTML funcional.

+
+
+
+
+

Recomendaciones para afrontar la tarea

+

Al enfrentarnos a un proyecto de cierta complejitud, el como afrontarlo resulta de cricial para el desarollo del mismo por ello a a continuación dejo un esquema de implementación modular. Sería mejor no utilizarlo, pero puede ser un buen punto de partida si no se sabe como empezar la app, no es el único proceso de implementación válido ni es más correcto que cualquier otro

+
    +
  1. Estructura de HTML básica contadores de versos y estrofas placeholders de poema y título y botón
  2. +
  3. Formateo CSS parte estática: centrado, tamaño (todo lo que no sea color)
  4. +
  5. Definir clases con colores predeterminados
  6. +
  7. Lógica interna con JS
  8. +
+
    +
  • Buscar palabra
  • +
  • Contar estrofas
  • +
  • Conteo versos
  • +
  • Selección de clase
  • +
  • Generar color aleatorio si procede
  • +
+
    +
  1. Integración con DOM
  2. +
+ + +
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/docs/pages/Bloque3/t9.pdf b/docs/pages/Bloque3/t9.pdf new file mode 100644 index 0000000..f62e76b Binary files /dev/null and b/docs/pages/Bloque3/t9.pdf differ diff --git a/docs/pages/rubric.html b/docs/pages/rubric.html index 29bc56d..d957112 100644 --- a/docs/pages/rubric.html +++ b/docs/pages/rubric.html @@ -504,6 +504,23 @@ MA: Uncontrolled fields y useRef + + + + diff --git a/docs/rubriuca.pdf b/docs/rubriuca.pdf index 4b88c58..557089c 100644 Binary files a/docs/rubriuca.pdf and b/docs/rubriuca.pdf differ diff --git a/docs/search.json b/docs/search.json index 407c574..6c29f53 100644 --- a/docs/search.json +++ b/docs/search.json @@ -206,17 +206,105 @@ "text": "Más ejemplos\nEj1: Show input\nEj2: Par e Impar\nEj3: Toggle\nEj4: Creación dinámica\nEj5: Validación básica" }, { - "objectID": "pages/Bloque3/MARef.html", - "href": "pages/Bloque3/MARef.html", - "title": "MA: Uncontrolled fields y useRef", + "objectID": "pages/Bloque3/MAcss2.html", + "href": "pages/Bloque3/MAcss2.html", + "title": "MA: CSS Flex y CSS", "section": "", - "text": "Por el momento hemos visto dos hooks useState y useEffect, pero recordemos que en React existen más tipos de hooks que por ser menos útiles y debido a la falta de tiempo no son explicados, no obstante si hay alguno digno de mención es useRef o las referencias.\nUna ref es una referencia mutable que permite acceder directamente a un elemento del DOM o almacenar un valor persistente sin provocar un re-render del componente. El siguiente video ilustra su uso. Es un poco largo pero sirve para repasar los otros hooks.\n\n\nCon las ref podemos introducir los uncontrolled fields que nos permiten trabajar de otra forma con los formularios.\n\nSe prefiere la segunda implementación (la que no utiliza referencias) sobre la primera.", + "text": "Además de las propiedades estudiadas de CSS también hay algunas críticas que debido a la falta de tiempo no se han podido explicar como es el caso de display a continuación estos dos vídeos profundizan en los modos flex y grid formas diferentes de diseñar la estructura de la página", "crumbs": [ "Bloque III Interacción", - "Semana 9", - "MA: *Uncontrolled fields* y `useRef`" + "Semana 6", + "MA: CSS Flex y CSS" + ] + }, + { + "objectID": "pages/Bloque3/ReactIV.html", + "href": "pages/Bloque3/ReactIV.html", + "title": "React IV", + "section": "", + "text": "Contenido", + "crumbs": [ + "Bloque III Interacción", + "Semana 10", + "React IV" + ] + }, + { + "objectID": "pages/Bloque3/ReactIV.html#ecosistema-node", + "href": "pages/Bloque3/ReactIV.html#ecosistema-node", + "title": "React IV", + "section": "Ecosistema Node", + "text": "Ecosistema Node\nHasta ahora hemos trabajado únicamente con React y JavaScript.\nSin embargo, en el desarrollo real de aplicaciones es muy común utilizar librerías externas, para ello podemos recurrir Node.JS.\nReact está diseñado para funcionar dentro de un ecosistema de paquetes.\nEjemplos habituales:\n\nReact Router → navegación\nAxios → peticiones HTTP\nChart.js → gráficas\nZustand / Redux → gestión de estado\nLibrerías de UI: Tailwind, Bootstrap, Booswatch", + "crumbs": [ + "Bloque III Interacción", + "Semana 10", + "React IV" + ] + }, + { + "objectID": "pages/Bloque3/ReactIV.html#npm", + "href": "pages/Bloque3/ReactIV.html#npm", + "title": "React IV", + "section": "npm", + "text": "npm\nnpm (Node Package Manager) es el sistema que permite instalar y gestionar librerías de JavaScript. Como su nombre indica, está desarrollado por Node.JS\nCada proyecto tiene un archivo:\npackage.json\nEn este archivo se registran las dependencias del proyecto.\nEjemplo:\n{\n \"dependencies\": {\n \"react\": \"^18.0.0\",\n \"react-router-dom\": \"^6.0.0\"\n }\n}\n\nInstalación de paquetes\nLas librerías se instalan desde la terminal.\nnpm install react-router-dom\nEsto hace tres cosas:\n\nDescarga el paquete\nLo guarda en node_modules (capreta donde se guardan las librerías externas)\nAñade la dependencia en package.json", + "crumbs": [ + "Bloque III Interacción", + "Semana 10", + "React IV" ] }, + { + "objectID": "pages/Bloque3/ReactIV.html#react-router", + "href": "pages/Bloque3/ReactIV.html#react-router", + "title": "React IV", + "section": "React Router", + "text": "React Router\nEn una aplicación web tradicional cada enlace carga una página nueva.\nEn React normalmente trabajamos con Single Page Applications (SPA).\nEn una SPA:\n\nel navegador no recarga la página\nReact cambia los componentes que se muestran\n\nPara gestionar esto utilizamos React Router.\nRealmente es la misma página, solo que el usuario lo percibe como distintas páginas\nEl usuario percibirá que el sitio web está divido en diferentes subpáginas\n\n/\npokemons\npokemons/pikachu\n\n\nComponentes principales de React Router\nLos elementos fundamentales son:\n\nBrowserRouter\nRoutes\nRoute\nLink\n\nEjemplo básico:\nimport { BrowserRouter, Routes, Route } from \"react-router-dom\";\n\nfunction App() {\n return (\n <BrowserRouter>\n\n <Routes>\n\n <Route path=\"/\" element={<Home />} />\n\n <Route path=\"/pokemons\" element={<PokemonList />} />\n\n </Routes>\n\n </BrowserRouter>\n );\n}\nElementos del código\n\nBrowserRouter\nEs el componente que activa el sistema de navegación de React Router. Utiliza la API de historial del navegador para cambiar la URL sin recargar la página.\nRoutes\nEs el contenedor donde se definen todas las rutas de la aplicación. React Router examina las rutas dentro de este componente para decidir qué componente mostrar.\nRoute\nDefine una ruta concreta de la aplicación.\n\n\npath\nIndica la URL que activa la ruta.\nEjemplo: / corresponde a la página principal.\nelement\nEs el componente de React que se renderiza cuando la URL coincide con el path.\n<Home />\nComponente que se muestra cuando el usuario accede a la ruta /.\n<PokemonList />\nComponente que se muestra cuando el usuario accede a la ruta /pokemons.\n\n\n\nNavegación\nPara navegar entre páginas utilizamos el componente Link.\nimport { Link } from \"react-router-dom\";\n\n<Link to=\"/\">Inicio</Link>\n\n<Link to=\"/pokemon\">Pokemon</Link>\nA diferencia de <a>:\n\nno recarga la página\nReact cambia el componente visible\n\n\n\nParámetros dinámicos\nPodemos crear rutas dinámicas.\nEjemplo:\n/pokemon/25\n/pokemon/7\nDefinición de la ruta:\n<Route path=\"/pokemon/:id\" element={<PokemonDetail />} />\n\nuseParams\nPara acceder al parámetro utilizamos el hook useParams de React Router.\nimport { useParams } from \"react-router-dom\";\n\nfunction PokemonDetail() {\n\n const { id } = useParams();\n\n return <p>Pokemon {id}</p>;\n\n}\nEste parámetro puede utilizarse para realizar peticiones a una API.", + "crumbs": [ + "Bloque III Interacción", + "Semana 10", + "React IV" + ] + }, + { + "objectID": "pages/Bloque3/ReactIV.html#context-api", + "href": "pages/Bloque3/ReactIV.html#context-api", + "title": "React IV", + "section": "Context API", + "text": "Context API\nEn aplicaciones grandes aparece un problema frecuente.\nMuchos componentes necesitan acceder a la misma información.\nPor ejemplo:\n\nusuario\ntema visual\nidioma\nconfiguración\n\nSi pasamos la información mediante props, los datos deben atravesar muchos componentes.\nRepresentación conceptual:\nApp\n └ Layout\n └ Page\n └ Component\nSi todos necesitan user, debemos pasar la prop continuamente.\nEste problema se conoce como prop drilling.\n\nContext\nReact proporciona una solución llamada Context.\nContext permite compartir información entre múltiples componentes sin pasar props manualmente.\nEl proceso tiene tres pasos:\n\nCrear el contexto\nProveer el contexto\nConsumir el contexto\n\n\nCrear un contexto\nimport { createContext } from \"react\";\n\nconst UserContext = createContext();\nEsto crea un contenedor que puede almacenar información compartida.\n\n\nProvider\nEl Provider permite que los componentes hijos accedan al contexto.\n<UserContext.Provider value={user}>\n\n <App />\n\n</UserContext.Provider>\nTodos los componentes dentro del Provider pueden acceder al valor.\n\n\nConsumir el contexto\nPara acceder al contexto utilizamos el hook useContext.\nimport { useContext } from \"react\";\n\nconst user = useContext(UserContext);\nEl componente obtiene directamente el valor almacenado en el contexto.\n\n\nEjemplo completo\nimport { createContext, useContext } from \"react\";\n\nconst UserContext = createContext();\n\nfunction App() {\n\n const user = { name: \"Javier\" };\n\n return (\n\n <UserContext.Provider value={user}>\n\n <Profile />\n\n </UserContext.Provider>\n\n );\n}\n\nfunction Profile() {\n\n const user = useContext(UserContext);\n\n return <h1>{user.name}</h1>;\n\n}", + "crumbs": [ + "Bloque III Interacción", + "Semana 10", + "React IV" + ] + }, + { + "objectID": "pages/Bloque3/presentacion-reactIV.html#ecosistema-node", + "href": "pages/Bloque3/presentacion-reactIV.html#ecosistema-node", + "title": "React IV", + "section": "Ecosistema Node", + "text": "Ecosistema Node\nHasta ahora hemos trabajado únicamente con React y JavaScript.\nSin embargo, en el desarrollo real de aplicaciones es muy común utilizar librerías externas, para ello podemos recurrir Node.JS.\nReact está diseñado para funcionar dentro de un ecosistema de paquetes." + }, + { + "objectID": "pages/Bloque3/presentacion-reactIV.html#npm", + "href": "pages/Bloque3/presentacion-reactIV.html#npm", + "title": "React IV", + "section": "npm", + "text": "npm\nnpm (Node Package Manager) es el sistema que permite instalar y gestionar librerías de JavaScript. Como su nombre indica, está desarrollado por Node.JS\nCada proyecto tiene un archivo:\npackage.json\nEn este archivo se registran las dependencias del proyecto." + }, + { + "objectID": "pages/Bloque3/presentacion-reactIV.html#react-router", + "href": "pages/Bloque3/presentacion-reactIV.html#react-router", + "title": "React IV", + "section": "React Router", + "text": "React Router\nEn una aplicación web tradicional cada enlace carga una página nueva.\nEn React normalmente trabajamos con Single Page Applications (SPA).\nEn una SPA:\n\nel navegador no recarga la página\nReact cambia los componentes que se muestran\n\nPara gestionar esto utilizamos React Router.\nRealmente es la misma página, solo que el usuario lo percibe como distintas páginas" + }, + { + "objectID": "pages/Bloque3/presentacion-reactIV.html#context-api", + "href": "pages/Bloque3/presentacion-reactIV.html#context-api", + "title": "React IV", + "section": "Context API", + "text": "Context API\nEn aplicaciones grandes aparece un problema frecuente.\nMuchos componentes necesitan acceder a la misma información.\nPor ejemplo:\n\nusuario\ntema visual\nidioma\nconfiguración\n\nSi pasamos la información mediante props, los datos deben atravesar muchos componentes." + }, { "objectID": "pages/Bloque3/ps.html", "href": "pages/Bloque3/ps.html", @@ -1377,17 +1465,73 @@ ] }, { - "objectID": "pages/Bloque3/MAcss2.html", - "href": "pages/Bloque3/MAcss2.html", - "title": "MA: CSS Flex y CSS", + "objectID": "pages/Bloque3/MARef.html", + "href": "pages/Bloque3/MARef.html", + "title": "MA: Uncontrolled fields y useRef", "section": "", - "text": "Además de las propiedades estudiadas de CSS también hay algunas críticas que debido a la falta de tiempo no se han podido explicar como es el caso de display a continuación estos dos vídeos profundizan en los modos flex y grid formas diferentes de diseñar la estructura de la página", + "text": "Por el momento hemos visto dos hooks useState y useEffect, pero recordemos que en React existen más tipos de hooks que por ser menos útiles y debido a la falta de tiempo no son explicados, no obstante si hay alguno digno de mención es useRef o las referencias.\nUna ref es una referencia mutable que permite acceder directamente a un elemento del DOM o almacenar un valor persistente sin provocar un re-render del componente. El siguiente video ilustra su uso. Es un poco largo pero sirve para repasar los otros hooks.\n\n\nCon las ref podemos introducir los uncontrolled fields que nos permiten trabajar de otra forma con los formularios.\n\nSe prefiere la segunda implementación (la que no utiliza referencias) sobre la primera.", "crumbs": [ "Bloque III Interacción", - "Semana 6", - "MA: CSS Flex y CSS" + "Semana 9", + "MA: *Uncontrolled fields* y `useRef`" ] }, + { + "objectID": "pages/Bloque3/t9.html", + "href": "pages/Bloque3/t9.html", + "title": "T6: Romancero Gitano I", + "section": "", + "text": "El objetivo de esta tarea es aplicar los conceptos básicos de HTML, CSS y JavaScript (DOM) para crear una página web interactiva que muestre poemas del Romancero gitano de Federico García Lorca y modifique su apariencia visual en función de las diferentes metáforas.\nResultado esperado" + }, + { + "objectID": "pages/Bloque3/t9.html#objetivo-de-la-tarea", + "href": "pages/Bloque3/t9.html#objetivo-de-la-tarea", + "title": "T6: Romancero Gitano I", + "section": "", + "text": "El objetivo de esta tarea es aplicar los conceptos básicos de HTML, CSS y JavaScript (DOM) para crear una página web interactiva que muestre poemas del Romancero gitano de Federico García Lorca y modifique su apariencia visual en función de las diferentes metáforas.\nResultado esperado" + }, + { + "objectID": "pages/Bloque3/t9.html#estructura-html", + "href": "pages/Bloque3/t9.html#estructura-html", + "title": "T6: Romancero Gitano I", + "section": "Estructura HTML", + "text": "Estructura HTML\nEl documento HTML debe:\n\nEstar correctamente estructurado (<!DOCTYPE>, <html>, <head>, <body>).\nContener un contenedor principal centrado horizontalmente.\nIncluir, en este orden:\n\nUn elemento para mostrar información métrica del poema (número de estrofas y versos).\nUn elemento para el título del poema.\nUn elemento para el texto del poema, respetando los saltos de verso utilizando la etiqueta <pre>.\nUn botón que permita cambiar de poema.\n\n\nNo debe utilizarse ningún framework ni librería externa." + }, + { + "objectID": "pages/Bloque3/t9.html#javascript", + "href": "pages/Bloque3/t9.html#javascript", + "title": "T6: Romancero Gitano I", + "section": "JavaScript", + "text": "JavaScript\n\nDatos\nEn JavaScript se debe definir un array de objetos, donde cada objeto represente un poema y tenga al menos:\n\nUn título.\nEl texto del poema como una cadena de texto, usando saltos de línea para los versos.\n\nEl cambio de poema debe hacerse recorriendo este array de forma cíclica (cola circular) mediante el botón.\nDescargar poemas (click derecho guardar enlace como)\n\n\nManipulación del DOM\nEl comportamiento de la página debe implementarse exclusivamente con DOM nativo, cumpliendo lo siguiente:\n\nTodas las funciones deben declararse como arrow functions.\nAl pulsar el botón:\n\nSe actualiza el título.\nSe actualiza el texto del poema.\nSe modifica el formato del fondo.\nSe recalculan y muestran:\n\nNúmero de versos.\nNúmero de estrofas (bloques separados por líneas en blanco).\n\n\n\nEl cálculo debe realizarse a partir del texto del poema, no con valores predefinidos." + }, + { + "objectID": "pages/Bloque3/t9.html#css", + "href": "pages/Bloque3/t9.html#css", + "title": "T6: Romancero Gitano I", + "section": "CSS", + "text": "CSS\nLorca utiliza las metáforas y la alegoría como elemento principal sobre el que construye sus poemas, al analizar profundamente descubrimos que siempre recurre a las mismas metáforas.\nEl color no se utiliza aquí solo como elemento decorativo, sino como un recurso semántico: cada color representa un símbolo literario presente en el poema.\nDesde el punto de vista técnico: - Los colores de fondo y de texto deben definirse en clases CSS. - JavaScript no decide colores, únicamente decide qué clase aplicar según el contenido del poema.\n\nPalabras clave y colores asociados\nSe debe detectar el texto del poema las siguientes palabras clave y aplicar el color de fondo correspondiente:\n\nguardia civil → fondo verde militar\nsangre → fondo granate oscuro\ncaballo → fondo color tierra\ncuchillo / navaja → fondo plateado\n\nEl color del texto debe elegirse siempre de forma que exista contraste suficiente con el fondo y se garantice la legibilidad.\nSi el poema contiene varias palabras clave, solo debe aplicarse un único estilo, siguiendo un orden de prioridad definido previamente.\nSi el poema no contiene ninguna de estas palabras, se aplicará un estilo por defecto con colores aleatorios." + }, + { + "objectID": "pages/Bloque3/t9.html#extra-opcional-símbolo-aurora", + "href": "pages/Bloque3/t9.html#extra-opcional-símbolo-aurora", + "title": "T6: Romancero Gitano I", + "section": "Extra opcional: símbolo aurora 🌈", + "text": "Extra opcional: símbolo aurora 🌈\nDe forma voluntaria, se puede añadir el símbolo aurora, que tendrá prioridad absoluta sobre todos los demás.\nCuando el poema contenga la palabra aurora, el fondo debe mostrar un degradado animado.\n\nCSS necesario para el extra\n.aurora {\n background: linear-gradient(120deg,\n #ff005d,\n #ff9f1c,\n #ffee32,\n #3cff00,\n #00e5ff,\n #7a00ff,\n #ff00c8\n );\n background-size: 600% 600%;\n animation: aurora 10s linear infinite;\n color: black;\n}\n\n@keyframes aurora {\n 0% { background-position: 0% 50%; }\n 50% { background-position: 100% 50%; }\n 100% { background-position: 0% 50%; }\n}" + }, + { + "objectID": "pages/Bloque3/t9.html#consejos", + "href": "pages/Bloque3/t9.html#consejos", + "title": "T6: Romancero Gitano I", + "section": "Consejos", + "text": "Consejos\n\nCentrado de la página (layout clásico)\nToda la página debe estar centrada horizontalmente.\nEl centrado se consigue mediante:\n\nUn contenedor con un ancho máximo definido.\nMárgenes automáticos a izquierda y derecha.\n\nDesde el punto de vista conceptual:\n\nmargin: 0 auto no centra texto, centra bloques.\nEl navegador reparte automáticamente el espacio sobrante a ambos lados del contenedor.\n\n\n\nAnimación del cambio de color\nPara evitar que los cambios de color sean bruscos, se utiliza la propiedad transition en CSS.\nEsta propiedad indica al navegador que los cambios en determinadas propiedades visuales deben hacerse de forma progresiva.\nEjemplo conceptual:\nbody {\n transition: background-color 0.6s, color 0.6s;\n}\nGracias a esta transición: - Cuando JavaScript cambia una clase o un color, - el navegador interpola automáticamente entre el color anterior y el nuevo.\nNo es necesario programar animaciones en JavaScript: CSS se encarga de todo el efecto visual.\n\n\nBúsqueda de una palabra\nPara buscar si determinada palabra determinada se debe utilizar la función includes de la clase string\n\ntexto = \"hoy nieva\";\n\ntexto.includes(\"nieva\"); //TRUE\ntexto.includes(\"llueve\"); //FALSE\n\n\nGeneración del color aleatorio\nPara la generacióndel color aleatorio de puede utilizar la siguiente función\nconst randomColor = () => '#' + Math.floor(Math.random() * 16777215).toString(16);\n\n\nConteo versos y estrofas\nEl recuento de versos y estrofas debe hacerse a partir del texto del poema, no con valores escritos a mano. A continuación se dan algunas pistas técnicas para abordar este problema.\n\nConteo de versos\nUn verso puede considerarse, a efectos prácticos en esta tarea, como una línea de texto no vacía.\nUna estrategia habitual consiste en: - Separar el texto por saltos de línea. - Eliminar las líneas vacías o formadas solo por espacios. - Contar cuántas líneas válidas quedan.\nEjemplo orientativo:\nconst versos = texto\n .split('\\n')\n .filter(linea => linea.trim() !== '')\n .length;\nEste enfoque es suficiente para la mayoría de los poemas del Romancero gitano y evita errores frecuentes.\n\n\nConteo de estrofas\nUna estrofa puede entenderse como un bloque de versos separado de otros bloques por una línea en blanco.\nUna posible estrategia es: - Separar el texto usando dos (o más) saltos de línea consecutivos. - Eliminar bloques vacíos. - Contar los bloques resultantes.\nEjemplo orientativo:\nconst estrofas = texto\n .split(/\\n\\s*\\n/)\n .filter(bloque => bloque.trim() !== '')\n .length;\nEntrega: un único archivo HTML funcional." + }, + { + "objectID": "pages/Bloque3/t9.html#recomendaciones-para-afrontar-la-tarea", + "href": "pages/Bloque3/t9.html#recomendaciones-para-afrontar-la-tarea", + "title": "T6: Romancero Gitano I", + "section": "Recomendaciones para afrontar la tarea", + "text": "Recomendaciones para afrontar la tarea\nAl enfrentarnos a un proyecto de cierta complejitud, el como afrontarlo resulta de cricial para el desarollo del mismo por ello a a continuación dejo un esquema de implementación modular. Sería mejor no utilizarlo, pero puede ser un buen punto de partida si no se sabe como empezar la app, no es el único proceso de implementación válido ni es más correcto que cualquier otro\n\nEstructura de HTML básica contadores de versos y estrofas placeholders de poema y título y botón\nFormateo CSS parte estática: centrado, tamaño (todo lo que no sea color)\nDefinir clases con colores predeterminados\nLógica interna con JS\n\n\nBuscar palabra\nContar estrofas\nConteo versos\nSelección de clase\nGenerar color aleatorio si procede\n\n\nIntegración con DOM" + }, { "objectID": "pages/Bloque3/reactI.html#sintaxis-jsx", "href": "pages/Bloque3/reactI.html#sintaxis-jsx", diff --git a/pages/Bloque3/ReactIV.qmd b/pages/Bloque3/ReactIV.qmd new file mode 100644 index 0000000..39d2979 --- /dev/null +++ b/pages/Bloque3/ReactIV.qmd @@ -0,0 +1,455 @@ +--- +title: "React IV" +subtitle: "Ecosistema npm, *React Router*, `useContext`" +author: "Javier Ribal del Río" +date: "2026-03-06" +date-modified: today +affiliation: "Hyperloop UPV" + +format: + html: default + revealjs: + history: false + chalkboard: true + output-file: presentacion-reactIV.html + parallax-background-image: ../../img/fondo.png + parallax-background-size: "cover" + pdf: default +format-links: + - pdf + - format: revealjs + text: Presentación + icon: file-slides +--- + +**Contenido** + +- Ecosistema React y paquetes npm +- Librerías externas +- React Router +- Parámetros de URL +- `useContext` + +::: {.content-visible when-format="revealjs"} + +--- + +::: + +## Ecosistema Node + +Hasta ahora hemos trabajado únicamente con **React y JavaScript**. + +Sin embargo, en el desarrollo real de aplicaciones es muy común utilizar **librerías externas**, para ello podemos recurrir `Node.JS`. + +React está diseñado para funcionar dentro de un **ecosistema de paquetes**. + +::: {.content-visible when-format="revealjs"} + +--- + +::: + + +Ejemplos habituales: + +- React Router → navegación +- Axios → peticiones HTTP +- Chart.js → gráficas +- Zustand / Redux → gestión de estado +- Librerías de UI: Tailwind, Bootstrap, Booswatch + +::: {.content-visible when-format="revealjs"} + +--- + +::: + +## npm + +npm (**Node Package Manager**) es el sistema que permite instalar y gestionar librerías de JavaScript. Como su nombre indica, está desarrollado por Node.JS + +Cada proyecto tiene un archivo: + +``` +package.json +``` + +En este archivo se registran las **dependencias del proyecto**. + +::: {.content-visible when-format="revealjs"} + +--- + +::: + +Ejemplo: + +```json +{ + "dependencies": { + "react": "^18.0.0", + "react-router-dom": "^6.0.0" + } +} +``` + +::: {.content-visible when-format="revealjs"} + +--- + +::: + +### Instalación de paquetes + +Las librerías se instalan desde la terminal. + +```bash +npm install react-router-dom +``` + +Esto hace tres cosas: + +1. Descarga el paquete +2. Lo guarda en `node_modules` (capreta donde se guardan las librerías externas) +3. Añade la dependencia en `package.json` + +::: {.content-visible when-format="revealjs"} + +--- + +::: + +## React Router + +En una aplicación web tradicional cada enlace carga **una página nueva**. + +En React normalmente trabajamos con **Single Page Applications (SPA)**. + +En una SPA: + +- el navegador no recarga la página +- React cambia los componentes que se muestran + +Para gestionar esto utilizamos **React Router**. + +*Realmente es la misma página, solo que el usuario lo percibe como distintas páginas* + +::: {.content-visible when-format="revealjs"} + +--- + +::: + +El usuario percibirá que el sitio web está divido en diferentes subpáginas + +- `/` +- `pokemons` +- `pokemons/pikachu` + +::: {.content-visible when-format="revealjs"} + +--- + +::: + +### Componentes principales de React Router + +Los elementos fundamentales son: + +- `BrowserRouter` +- `Routes` +- `Route` +- `Link` + +Ejemplo básico: + +::: {.content-visible when-format="revealjs"} + +--- + +::: + + + + + + + + +```jsx {.html code-line-numbers="|5,15|7,13|9,11,|9|11"} +import { BrowserRouter, Routes, Route } from "react-router-dom"; + +function App() { + return ( + + + + + } /> + + } /> + + + + + ); +} +``` + +::: {.content-visible when-format="revealjs"} + +--- + +::: + +**Elementos del código** + +- **`BrowserRouter`** + Es el componente que activa el sistema de navegación de React Router. Utiliza la API de historial del navegador para cambiar la URL sin recargar la página. +- **`Routes`** + Es el contenedor donde se definen todas las rutas de la aplicación. React Router examina las rutas dentro de este componente para decidir qué componente mostrar. +- **`Route`** + Define una ruta concreta de la aplicación. + +::: {.content-visible when-format="revealjs"} + +--- + +::: + +- **`path`** + Indica la URL que activa la ruta. + Ejemplo: `/` corresponde a la página principal. +- **`element`** + Es el componente de React que se renderiza cuando la URL coincide con el `path`. +- **``** + Componente que se muestra cuando el usuario accede a la ruta `/`. +- **``** + Componente que se muestra cuando el usuario accede a la ruta `/pokemons`. + +::: {.content-visible when-format="revealjs"} + +--- + +::: + + +### Navegación + +Para navegar entre páginas utilizamos el componente `Link`. + +```jsx +import { Link } from "react-router-dom"; + +Inicio + +Pokemon +``` + +A diferencia de ``: + +- **no recarga la página** +- React cambia el componente visible + +::: {.content-visible when-format="revealjs"} + +--- + +::: + +### Parámetros dinámicos + +Podemos crear rutas dinámicas. + +Ejemplo: + +``` +/pokemon/25 +/pokemon/7 +``` + +Definición de la ruta: + +```jsx +} /> +``` + +::: {.content-visible when-format="revealjs"} + +--- + +::: + +#### useParams + +Para acceder al parámetro utilizamos el hook `useParams` de *React Router*. + +```jsx +import { useParams } from "react-router-dom"; + +function PokemonDetail() { + + const { id } = useParams(); + + return

Pokemon {id}

; + +} +``` + +Este parámetro puede utilizarse para realizar peticiones a una API. + +::: {.content-visible when-format="revealjs"} + +--- + +::: + +## Context API + +En aplicaciones grandes aparece un problema frecuente. + +Muchos componentes necesitan acceder a la **misma información**. + +Por ejemplo: + +- usuario +- tema visual +- idioma +- configuración + +Si pasamos la información mediante *props*, los datos deben atravesar muchos componentes. + +::: {.content-visible when-format="revealjs"} + +--- + +::: + +Representación conceptual: + +``` +App + └ Layout + └ Page + └ Component +``` + +Si todos necesitan `user`, debemos pasar la prop continuamente. + +Este problema se conoce como **prop drilling**. + +::: {.content-visible when-format="revealjs"} + +--- + +::: + +### Context + +React proporciona una solución llamada **Context**. + +Context permite **compartir información entre múltiples componentes** sin pasar props manualmente. + +El proceso tiene tres pasos: + +1. Crear el contexto +2. Proveer el contexto +3. Consumir el contexto + +::: {.content-visible when-format="revealjs"} + +--- + +::: + +#### Crear un contexto + +```jsx +import { createContext } from "react"; + +const UserContext = createContext(); +``` + +Esto crea un contenedor que puede almacenar información compartida. + +::: {.content-visible when-format="revealjs"} + +--- + +::: + +#### Provider + +El `Provider` permite que los componentes hijos accedan al contexto. + +```jsx + + + + + +``` + +Todos los componentes dentro del `Provider` pueden acceder al valor. + +::: {.content-visible when-format="revealjs"} + +--- + +::: + +#### Consumir el contexto + +Para acceder al contexto utilizamos el hook `useContext`. + +```jsx +import { useContext } from "react"; + +const user = useContext(UserContext); +``` + +El componente obtiene directamente el valor almacenado en el contexto. + +::: {.content-visible when-format="revealjs"} + +--- + +::: + +#### Ejemplo completo + +```jsx +import { createContext, useContext } from "react"; + +const UserContext = createContext(); + +function App() { + + const user = { name: "Javier" }; + + return ( + + + + + + + + ); +} + +function Profile() { + + const user = useContext(UserContext); + + return

{user.name}

; + +} +``` + +::: {.content-visible when-format="revealjs"} + +--- + +::: diff --git a/pages/Bloque3/t9.qmd b/pages/Bloque3/t9.qmd new file mode 100644 index 0000000..d6eed7a --- /dev/null +++ b/pages/Bloque3/t9.qmd @@ -0,0 +1,242 @@ +--- +title: "T6: Romancero Gitano I" +author: "Javier Ribal del Río" +date: "2025-12-19" +date-modified: today +affiliation: "Hyperloop UPV" +--- + +## Objetivo de la tarea + +El objetivo de esta tarea es aplicar los conceptos básicos de HTML, CSS y JavaScript (DOM) para crear una página web interactiva que muestre poemas del *Romancero gitano* de Federico García Lorca y modifique su apariencia visual en función de las diferentes metáforas. + + +[Resultado esperado](romancero_gitano_web_interactiva.html) + + + +## Estructura HTML + +El documento HTML debe: + +- Estar correctamente estructurado (``, ``, ``, ``). +- Contener un **contenedor principal** centrado horizontalmente. +- Incluir, en este orden: + 1. Un elemento para mostrar **información métrica** del poema (número de estrofas y versos). + 2. Un elemento para el **título del poema**. + 3. Un elemento para el **texto del poema**, respetando los saltos de verso utilizando la etiqueta `
`.
+  4. Un **botón** que permita cambiar de poema.
+
+No debe utilizarse ningún *framework* ni librería externa.
+
+
+## JavaScript
+
+### Datos
+
+En JavaScript se debe definir un **array de objetos**, donde cada objeto represente un poema y tenga al menos:
+
+- Un título.
+- El texto del poema como una cadena de texto, usando saltos de línea para los versos.
+
+El cambio de poema debe hacerse recorriendo este array de forma cíclica (cola circular) mediante el botón.
+
+[Descargar poemas](poemas.js) (click derecho guardar enlace como)
+
+
+###  Manipulación del DOM
+
+El comportamiento de la página debe implementarse **exclusivamente con DOM nativo**, cumpliendo lo siguiente:
+
+- Todas las funciones deben declararse como **arrow functions**.
+- Al pulsar el botón:
+  - Se actualiza el título.
+  - Se actualiza el texto del poema.
+  - Se modifica el formato del fondo.
+  - Se recalculan y muestran:
+    - Número de versos.
+    - Número de estrofas (bloques separados por líneas en blanco).
+
+El cálculo debe realizarse a partir del texto del poema, no con valores predefinidos.
+
+
+## CSS
+
+Lorca utiliza las metáforas y la alegoría como elemento principal sobre el que construye sus poemas, al analizar profundamente descubrimos que siempre recurre a las mismas metáforas.
+
+El color no se utiliza aquí solo como elemento decorativo, sino como un recurso semántico: cada color representa un símbolo literario presente en el poema.
+
+Desde el punto de vista técnico:
+- Los **colores de fondo y de texto** deben definirse en **clases CSS**.
+- JavaScript no decide colores, únicamente decide qué clase aplicar según el contenido del poema.
+
+
+### Palabras clave y colores asociados
+
+Se debe detectar el texto del poema las siguientes **palabras clave** y aplicar el **color de fondo correspondiente**:
+
+- **guardia civil** → fondo **verde militar**
+- **sangre** → fondo **granate oscuro**
+- **caballo** → fondo **color tierra**
+- **cuchillo / navaja** → fondo **plateado**
+
+El color del texto debe elegirse siempre de forma que exista **contraste suficiente** con el fondo y se garantice la legibilidad.
+
+Si el poema contiene varias palabras clave, solo debe aplicarse **un único estilo**, siguiendo un orden de prioridad definido previamente.
+
+Si el poema no contiene ninguna de estas palabras, se aplicará un **estilo por defecto** con colores aleatorios.
+
+
+
+## Extra opcional: símbolo *aurora* 🌈
+
+De forma **voluntaria**, se puede añadir el símbolo **`aurora`**, que tendrá **prioridad absoluta sobre todos los demás**.
+
+Cuando el poema contenga la palabra `aurora`, el fondo debe mostrar un **degradado animado**.
+
+### CSS necesario para el extra
+
+```css
+.aurora {
+  background: linear-gradient(120deg,
+    #ff005d,
+    #ff9f1c,
+    #ffee32,
+    #3cff00,
+    #00e5ff,
+    #7a00ff,
+    #ff00c8
+  );
+  background-size: 600% 600%;
+  animation: aurora 10s linear infinite;
+  color: black;
+}
+
+@keyframes aurora {
+  0%   { background-position: 0% 50%; }
+  50%  { background-position: 100% 50%; }
+  100% { background-position: 0% 50%; }
+}
+```
+
+---
+
+## Consejos
+
+### Centrado de la página (layout clásico)
+
+Toda la página debe estar centrada **horizontalmente**.
+
+El centrado se consigue mediante:
+
+- Un contenedor con un ancho máximo definido.
+- Márgenes automáticos a izquierda y derecha.
+
+Desde el punto de vista conceptual:
+
+- `margin: 0 auto` **no centra texto**, centra **bloques**.
+- El navegador reparte automáticamente el espacio sobrante a ambos lados del contenedor.
+
+
+### Animación del cambio de color
+
+Para evitar que los cambios de color sean bruscos, se utiliza la propiedad **`transition`** en CSS.
+
+Esta propiedad indica al navegador que los cambios en determinadas propiedades visuales deben hacerse de forma progresiva.
+
+Ejemplo conceptual:
+
+```css
+body {
+  transition: background-color 0.6s, color 0.6s;
+}
+```
+
+Gracias a esta transición:
+- Cuando JavaScript cambia una clase o un color,
+- el navegador interpola automáticamente entre el color anterior y el nuevo.
+
+No es necesario programar animaciones en JavaScript: **CSS se encarga de todo el efecto visual**.
+
+
+### Búsqueda de una palabra
+
+Para buscar si determinada palabra determinada se debe utilizar la función `includes` de la clase string
+
+```js
+
+texto = "hoy nieva";
+
+texto.includes("nieva");    //TRUE
+texto.includes("llueve");   //FALSE
+```
+
+
+### Generación del color aleatorio
+
+Para la generacióndel color aleatorio de puede utilizar la siguiente función 
+
+```js
+const randomColor = () => '#' + Math.floor(Math.random() * 16777215).toString(16);
+```
+
+### Conteo versos y estrofas
+
+El recuento de versos y estrofas debe hacerse **a partir del texto del poema**, no con valores escritos a mano. A continuación se dan algunas **pistas técnicas** para abordar este problema.
+
+#### Conteo de versos
+
+Un verso puede considerarse, a efectos prácticos en esta tarea, como **una línea de texto no vacía**.
+
+Una estrategia habitual consiste en:
+- Separar el texto por saltos de línea.
+- Eliminar las líneas vacías o formadas solo por espacios.
+- Contar cuántas líneas válidas quedan.
+
+Ejemplo orientativo:
+
+```js
+const versos = texto
+  .split('\n')
+  .filter(linea => linea.trim() !== '')
+  .length;
+```
+
+Este enfoque es suficiente para la mayoría de los poemas del *Romancero gitano* y evita errores frecuentes.
+
+#### Conteo de estrofas
+
+Una estrofa puede entenderse como un **bloque de versos separado de otros bloques por una línea en blanco**.
+
+Una posible estrategia es:
+- Separar el texto usando dos (o más) saltos de línea consecutivos.
+- Eliminar bloques vacíos.
+- Contar los bloques resultantes.
+
+Ejemplo orientativo:
+
+```js
+const estrofas = texto
+  .split(/\n\s*\n/)
+  .filter(bloque => bloque.trim() !== '')
+  .length;
+```
+
+
+
+**Entrega:** un único archivo HTML funcional.
+
+## Recomendaciones para afrontar la tarea
+
+Al enfrentarnos a un proyecto de cierta complejitud, el como afrontarlo resulta de cricial para el desarollo del mismo por ello a a continuación dejo un esquema de implementación modular.  Sería mejor no utilizarlo, pero puede ser un buen punto de partida si no se sabe como empezar la app, no es el único proceso de implementación válido ni es más correcto que cualquier otro
+
+1. Estructura de HTML básica contadores de versos y estrofas *placeholders* de poema y título y botón
+2. Formateo CSS parte estática: centrado, tamaño (todo lo que no sea color)
+3. Definir clases con colores predeterminados
+4. Lógica interna con JS
+  - Buscar palabra
+  - Contar estrofas
+  - Conteo versos
+  - Selección de clase 
+  - Generar color aleatorio si procede
+5. Integración con DOM
\ No newline at end of file