Jose Luis Bedoya
este profe es demasiao' bueno
Las rutas dinámicas son la base de cualquier app moderna que muestre contenido distinto según la URL: un blog post, una clase, un perfil. Con useParams de React Router Dom v6 puedes leer ese fragmento variable de la URL (el slug) y renderizar contenido distinto reutilizando un mismo componente. Esta guía te muestra cómo hacerlo paso a paso usando un blog como ejemplo.
Qué es un slug y por qué importa en una ruta dinámica
Imagina que entras a platzi.com/clases/como-aprender-react. Esa última parte, como-aprender-react, es el slug: el identificador único que le dice a tu app qué contenido mostrar dentro de una misma plantilla [02:15]. La estructura de la vista (videoplayer, título, profesor, comentarios) se mantiene, pero el contenido cambia según ese identificador.
En React Router defines ese segmento variable con dos puntos seguidos del nombre, así: /blog/:slug. Lo que sea que venga después de /blog/ queda capturado bajo esa variable y disponible para tu componente.
¿Qué es un slug en una URL? Es la parte final y legible que identifica un recurso único, como
que-es-reacten/blog/que-es-react. Funciona como una llave para buscar el contenido correcto.
Cómo construir la lista de enlaces con datos simulados
Antes de leer parámetros, necesitas algo que enlace hacia esas rutas dinámicas. La idea es tener un arreglo blogData con objetos que contengan al menos title, slug, content y author, y luego mapearlo en la página del blog [05:40].
La estructura queda así:
blogData.js que exporta el arreglo con los posts.BlogPage que importa blogData y hace .map sobre él.BlogLink que recibe el post por props y renderiza un <Link> apuntando a /blog/${post.slug}.jsx
function BlogLink({ post }) {
return (
<li>
<Link to={/blog/${post.slug}}>{post.title}</Link>
</li>
);
}
Cada slug debe ser único, porque dos URLs idénticas no pueden coexistir en el enrutador. Si necesitas otro identificador interno, agrégalo como propiedad aparte (por ejemplo id), pero el slug manda en la URL.
Cómo leer parámetros de la URL con useParams
Aquí entra la pieza clave. Cuando defines la ruta como /blog/:slug en tu App.js, React Router guarda ese valor y te lo entrega a través del hook useParams, que importas desde react-router-dom [10:25].
Dentro de tu componente BlogPost lo usas con desestructuración:
jsx import { useParams } from 'react-router-dom'; import { blogData } from './blogData';
function BlogPost() { const { slug } = useParams(); const blogPost = blogData.find(post => post.slug === slug);
return ( <> <h2>{blogPost.title}</h2> <p>{blogPost.author}</p> <p>{blogPost.content}</p> </> ); }
Fíjate en el flujo: useParams te devuelve el slug desde la URL, luego usas .find() sobre el arreglo para localizar el post que coincida, y finalmente renderizas sus campos. En una app real, ese .find() se reemplaza por una llamada a una API que reciba el slug como parámetro.
¿Qué devuelve useParams en React Router 6? Devuelve un objeto con todas las variables definidas en la ruta con
:. Si tu ruta es/blog/:slug, obtienes{ slug: 'valor-de-la-url' }.
Por qué separar blogData en su propio archivo
Mover el arreglo blogData a un archivo independiente permite que tanto BlogPage (la lista) como BlogPost (el detalle) lo importen sin duplicar datos [13:50]. Es un patrón básico de organización que te prepara para sustituir esos datos por una capa de servicios real.
Cómo se ve el resultado de una ruta dinámica funcional
Cuando todo está conectado, la magia se nota: entras a /blog, ves la lista de publicaciones, haces clic en ¿Qué es React? y aterrizas en /blog/que-es-react con el título, autor y contenido específicos. Cambias a /blog/que-es-vue y el mismo componente BlogPost se rellena con datos distintos, sin que tú hayas escrito una ruta manual por cada post.
Esa es la potencia de las rutas dinámicas: un solo componente, infinito contenido, todo gobernado por el slug de la URL y la lectura que useParams hace de ella.
En la siguiente entrega vas a conocer useNavigate, otro hook de React Router Dom que te permite cambiar de ruta sin depender de los componentes Link o NavLink. ¿Ya estás usando rutas dinámicas en algún proyecto? Cuéntame en los comentarios cómo las estructuras tú.
useParams: rutas dinámicas
¿Qué son las rutas dinámicas?
Digamos que tenemos una aplicación la cual nos envía a cierto contenido, ejemplo aplicación/blog/como-aprender-react, esta ultima parte en negro se llama slug, lo que nos permite es tener una base en la que exponer cierto contenido, pero intercalando la información en caso de que el slug cambie también.
Por ejemplo, en caso de que cambiemos el enlace pero la base sea la misma ejemplo: aplicación/blog/como-aprender-svelte, nos daríamos cuenta de que la maquetación sigue siendo la misma, solo que tiene diferente información, ya que si el slug cambia, el contenido cambia, pero como parte de una sola base, tiene la misma composición pero diferente contenido.
Un ejemplo rápido de las rutas dinámicas son los perfiles en Facebook, tienen la misma composición, tienen una foto de perfil, de portada, un nombre, información del usuario, estados y publicaciones; pero el perfil de Juanita no es el mismo que el de Pepe, ya que cada uno tiene información diferente porque son personas diferentes y publican diferente contenido.
Creemos nuestras rutas dinámicas
Vamos a hacer nuestras rutas dinámicas en nuestro componente de BlogPage:
import React from 'react'; import { Link } from 'react-router-dom'; import { blogdata } from '../Data/blogdata' /* Como en nuestro anterior componente, aquí cargarémos la información de manera dinámica por medio de un arreglo, para que nuestro código sea más mantenible a futuro y evitar duplicidad y crear verdaderos componentes */ function BlogPage() { return ( <> <h2>Blog Page</h2> <ul> {blogdata.map( post => ( <BlogLink post={post} /> ))} </ul> </> ); } /* Este BlogLink srá el que contenga los datos que nos crearan nuestro slug y nos redireccionen al contenido que deseamos ver */ function BlogLink({ post }) { return ( <li> <Link to={`/blog/${post.slug}`} >{post.title}</Link> </li> ); } export { BlogPage }
blogdata.js
/* Este Array simula una API que contenga nuestros datos, estos cargarán dinámicamente el contenido a los fake blogs */ const blogdata = []; blogdata.push({ title: '¿Que es React?', slug: 'que-es-react', content: 'React es el mejor Framework de JavaScript, que lindo React', author: 'Andrés Rodríguez' }); blogdata.push({ title: '¿Que es Vue?', slug: 'que-es-vue', content: 'Vue es el mejor Framework de JavaScript, que lindo Vue', author: 'Andrés Rodríguez' }); blogdata.push({ title: '¿Que es Angular?', slug: 'que-es-angular', content: 'Angular esta bien, que lindo React XD', author: 'Andrés Rodríguez' }); blogdata.push({ title: '¿Que es Svelte?', slug: 'que-es-svelte', content: 'Svelte es el mejor Framework de JavaScript, que lindo Svelte', author: 'Andrés Rodríguez' });
Una vez tenemos esto, debemos hacer que nuestros componentes se traqueen en la aplicación. Para esto debemos ir a App.js e ir a nuestro componente correspondiente y a continuación en su path después de su ruta debemos indicarle seguido de dos puntos, cual es el nombre de la variable en la cual tenemos nuestra nueva ruta. Veamos como:
// Importamos el componente de una vez ... import { BlogPost } from './Components/Routes/BlogPost/BlogPost'; function App() { return ( <> <HashRouter> ... <Routes> ... {/* En este caso la ruta dinámica se almacena en "slug" */} <Route path='/blog/:slug' element={<BlogPage />} /> </Routes> </HashRouter> </> ) }
Ahora todos esos cambios dinámicos se van a poder detectar y renderizar. Aún así debemos crear el componente que se renderice, entonces hagámoslo, este será el BlogPost.js.
import React from 'react'; // Importamos el useParams import { Link, useParams } from 'react-router-dom'; // También necesitamos los datos aquí import { blogdata } from '../Data/blogdata' function BlogPost() { /* Para cargar la información dinámicamente en la página debemos hacer uso del "useParams", este por medio de un objeto que debemos destructurar nos traerá el slug */ const { slug } = useParams(); /* Lo que hacemos por acá es encontrar la información que necesitamos mediante una confición en un fin que nos envíe y guarde en esta variable los datos del post cuyo slug coincida con el que estamos solicitando por un compoente para que se renderice */ const blogpost = blogdata.find( post => post.slug == slug ); /* Ahora si, después de que encontremos la información que necesitamos podemos cargarla en nuestro componente y renderizarla */ return ( <> <h3>{blogpost.title}</h3> <p>{blogpost.author}</p> <p>{blogpost.content}</p> </> ); } export { BlogPost }
Y si probamos veremos que ya está cargando nuestro contenido, hemos aprendido a crear rutas dinámicas con React 😀.
Una pequeña correccion. Dentro de App.jsx se incluye la ruta dinámica (slug) al elemento BlogPost, es decir que el codigo resumido quedaría algo asi:
// Importamos el componente de una vez ... import { BlogPost } from './Components/Routes/BlogPost/BlogPost'; function App() { return ( <> <HashRouter> ... <Routes> ... <Route path='/blog' element={<BlogPage />} /> {/* En este caso la ruta dinámica se almacena en "slug" */} <Route path='/blog/:slug' element={<BlogPost />} /> </Routes> </HashRouter> </> ) }
Gracias a los useParams podemos renderizar información de manera dinámica. Para lograr esto lo que debemos a hacer es, en nuestro router, especificamos el path que vamos a utilizar:
Imaginemos que tenemos una página donde guardamos blogs y que al, darle click a estos, nos envían a una nueva página, en nuestro router vamos a tener algo parecido a esto:
... <Route path='/blog' element={<BlogPage/>}/> <Route path='/blog/:slug' element={<BlogPost/>}/> ...
La primera del path es igual que la de su ruta superior, lo que sucede luego es que volvemos a poner un slash seguido de dos puntos y el nombre del parámetro.
Una vez definido el parámetro, dentro de BlogPage vamos a definir los links y sus respectivos paths que continuarán desde blog y dentro de BlogPost llamaríamos al Hook.
export function BlogPost() { const {slug} = useParams() const blogpost = blogdata.find(post => post.slug === slug) return ( <> <h3>{blogpost.title}</h3> <p>{blogpost.content}</p> </> ) }
Con el Hook vamos a poder hacer uso del path que enviamos desde BlogPage. Luego, por medio de una función de filtrado, vamos a encontrar el objeto correspondiente a ese path, para asi mostrarlo.
Jose Luis Bedoya
este profe es demasiao' bueno
Fabián Nava Pereda
En este video el proyecto final hacen un llamado al api dependiendo del id linkeado y mucho mas para su repositorio y practica.
<Link to={`/cocktail${id}`} />
const SingleCocktail = () => { const {id} = useParams() try{ const response = await fetch(`${url}${id}`) ... } }
Un pequeño ejemplo.
Abel da Cunha
Se va mucho por las ramas con un tema que es complicado... si sintetizara más sería un buen curso.
Rodrigo Andrés Moreno Pertúz
Para mi si programas de forma convencionada, si lees e investigas cuales son estas convenciones, si se es mas framework que biblioteca. pero bueno
Jose Tellez
Esto de rutas dinamicas es como cuando en un Ecommerce vas y cambias entre productos, la base de la url es la misma, lo que cambia es lo ultimo, el slug
La logica es:
Cuando entras al blog, producto, la clase, etc. Seteas el slug. Basicamente, seteas la url. Pero esa url no existe, no está trackeada.
Vas al app.js o donde sea que tengas el proveedor de rutas y renderizas algo como
<Route path="/blog/:slug" element={<BlogPost />} />
Dentro del componente <BlogPost /> obtienes el slug a traves de useParams(). Con ese slug puedes encontrar el objeto cuyo slug sea el mismo y así ya tienes la información para renderizar.
Basicamente, seteas la url con un slug personalizado. Renderizar un componente cuyo path tiene esa sintaxis “/:slug” despues del url base. Ese slug lo obtienes en el componente a renderizar para poder obetener la inforamción a renderizar. Renderizas.
Diego Reyes Cabrera
Hasta el momento, no se ha explicado "bien" qué es exactamente un slug. Este link me sirvió Medium
Harold Zurita Simon
Samuel Miranda Martínez
Tengo unas dudas que no tienen que ver con el tema:
El profesor define el nuevo componente con function, eso es por estándar o gusto personal? o es porque el código aburrido es mejor?
Se declaran los arrays primero y después se le agregan con push los elementos, hay algún motivo o también se puede inicializar con los elementos de una vez. _ Ejemplo: const data = [{...},{...},{...}] _
Existirá un juandclint o una configuración del linter, para ser así de organizado como el súper sensei? Cierto que hay una configuración del linter para obligar las exportaciones nombradas?
Juan Castro
ProfesorJonathan Amaya Mendieta
Jose Ever Muñoz Muñoz
exacto, siempre lo hago asi, pero al profe le gusta usar exports nombrados
Jonathan Stiven Colorado Largo
Si de casualidad estas intentando arreglar el issue o Warning : Each child ina list should have a unique "key" prop, se soluciona en el siguiente video, eso si deberías tener funcionando todo como se ve en el video
Carlos Rodríguez
Que hook se usa para obtener los quer params de una url con estas, por ejemplo: www.localhost:5050/?title=react&author=carlos
Juan Castro
ProfesorCarlos Rodríguez
Gracias profe @juandc
Jesus Heriberto Lara Juarez
Angular muirio xD
David Rangel
Juan Diego Mejia Maestre
Alvaro H. Ruiz V.
PreGunTa! Según esto, en App() ya no puedo hacer una composición de componentes, debo desglosar en tantas secciones tenga el sitio web y en cada una hacer la respectiva composición, correcto?
Juan Castro
ProfesorEsa es una opción, correcto. :D
Gustavo A. González G.
Cómo se haría para mostrar una vista que indique que la url es inválida? Para los casos en los que el slug ingresado no se encuentre definido. Gracias 🙏🏻
Juan Castro
ProfesorPuro JS. Si el id del TODO existe dentro de --en este caso-- la lista de TODOs, render normal, si no, un 404 o incluso redirect automático al home. :D
Abraham Gonzalez
Tendrias que hacer la validación dentro del componente. Por ejemplo tenemos BlogPost con la siguiente ruta localhost:5173/#/blog/este-slug-no-existe no tendremos un error tan solo tendremos nuestra pagina en blanco.
Queda de nuestra parte dentro del componente/vista BlogPost validar que si slug.id (por tomar algun ejemplo) no exsite nos redireccione a una vista 404 o mejor aun una vista que nos indique que el post no existe o fue eliminado y nos sugiera otros posts.
Gualberto Montiel
Osea que a medida que incrementa el uso de dependecias o librerias React Js se considera como un Framework?
Juan Castro
ProfesorEmpieza a funcionar mucho más como framework que como librería, sí. Aunque hace poco Dan Abramov mencionó eso mismo pero con arquitectura en vez de framework. Tiene todo el sentido del mundo. Super interesante. :D
Gilbert Ardila
Cayo Legal
Te falta el atributo end. Queda de esta manera
<NavLink end style={({isActive})=>({color: isActive? 'red':'blue'})} to={route.to}> {route.text} </NavLink>
Gilbert Ardila
useParams: rutas dinámicas
.
Vamos a crear un componente BlogPage que va a recorrer un array desde un archivo blogData, dicho array contiene información general de los posts. Sin embargo, la información más importante será el slug puesto que utilizaremos esta propiedad para distinguir las rutas dinámicas para los posts.
.
import React from 'react'; import { Link } from 'react-router-dom'; import { blogdata } from './blogdata' function BlogPage(){ return( <> <h2>BlogPage</h2> <ul> {blogdata.map(post=>(<BlogLink post={post}/>))} </ul> </> ); } function BlogLink({post}){ return( <li> <Link to={`/blog/${post.slug}`}>{post.title}</Link> </li> ); } export{BlogPage};
const blogdata=[]; blogdata.push({ title:'¿Qué es React?', slug:'que-es-react', content:'React es el mejor framework de JavaScript.', author:'juandc', }); blogdata.push({ title:'¿Qué es Vue?', slug:'que-es-vue', content:'Vue es el mejor framework de JavaScript.', author:'diannerd', }); blogdata.push({ title:'¿Qué es Angular?', slug:'que-es-angular', content:'Angular es el mejor framework de JavaScript.', author:'nicobytes', }); export{blogdata};
.
Dentro del componente App, si deseamos establecer rutas para cada publicación en nuestro array, la opción convencional nos obligaría a crear múltiples rutas, variando únicamente el slug final.
.
No obstante, al emplear rutas dinámicas, solo necesitamos definir una única ruta, /blog/:slug, donde los dos puntos denotan su naturaleza dinámica. Lo que sigue después indicará la parte variable, que puede adoptar cualquier valor o nombre, en este caso, el slug.
.
function App() { return ( <> <HashRouter> <Menu /> <Routes> <Route path="/" element={<HomePage />} /> <Route path="/blog" element={<BlogPage />} /> <Route path="/blog/:slug" element={<BlogPost />} /> <Route path="/profile" element={<ProfilePage />} /> <Route path="*" element={<p>Not found</p>} /> </Routes> </HashRouter> </> ); }
.
Finalmente, utilizaremos el React Hook useParams para obtener el parámetro o la parte variable de la ruta dinámica, que en este caso es el slug. Luego, emplearemos esta información para buscar el post correspondiente dentro del array de posts y renderizar sus datos utilizando el componente BlogPost.
.
import React from 'react'; import { Link, useParams } from 'react-router-dom'; import { blogdata } from './blogdata' function BlogPost() { const { slug } = useParams(); const blogpost = blogdata.find(post => post.slug === slug); return ( <> <h3>{blogpost.title}</h3> <p>{blogpost.author}</p> <p>{blogpost.content}</p> </> ); } export { BlogPost };
Tanto para los componentes como para la información del blog podemos exportar todo desde una sona línea. Como por ejemplo:
export const blogData = [ { title: "¿Qué es React?", slug: "que-es-react", content: "React es el mejor framework de JavaScript.", author: "tatanlion", }, { title: "¿Qué es Vue?", slug: "que-es-vue", content: "Vue es el mejor framework de JavaScript.", author: "tatanlion", }, { title: "¿Qué es Angular?", slug: "que-es-angular", content: "Angular es el mejor framework de JavaScript.", author: "tatanlion", }, ]; ```Tan solo agregando la palabra export antes, para el caso de los componentes es igual export const Menu = () => { 	.... Código del componente... }
Así queda la sección del Blog con Typescript y también con algo de feedback de sonarqube Qué es SonarQube: Verifica y analiza la calidad de tu código que al hacer el mapping del los blog post, te pide una key para los componentes:
import React from "react"; import { Link } from "react-router"; import { blogData } from "../chore/db"; type PostType = { slug: string; title: string; content?: string; author?: string; }; type PostComponent = { post: PostType; }; export const Blog = () => { return ( <> <h1>Blog</h1> <ul> {blogData.map((post) => ( <React.Fragment key={post.slug}> <BlogLink post={post} /> </React.Fragment> ))} </ul> </> ); }; const BlogLink = ({ post }: PostComponent) => { return ( <li> <Link to={`/blog/${post.slug}`}>{post.title}</Link> </li> ); };
🧠 Rutas Dinámicas en React: El Patrón /:slug
Este patrón es crucial para el desarrollo web moderno. Permite usar un único componente (BlogPost) para mostrar múltiples contenidos (publicaciones, productos, servicios) al leer el identificador único de la URL.
1. Conceptos Fundamentales
Para entender las rutas dinámicas, necesitamos tres piezas clave:
platzi.com/clases/como-aprender-react, el slug es como-aprender-react.:) para marcar una variable en la URL./blog/:slug.useParams() Hook:
2. Implementación Paso a Paso
El proceso completo se basa en la coordinación de la fuente de datos, los enlaces y el componente de detalle.
A. La Fuente de Datos
Tus datos (simulando una respuesta de API) deben tener un campo slug que sea único para cada elemento.
JavaScript
// blogData.js (Arreglo de datos) export const blogData = [ { slug: "que-es-react", title: "¿Qué es React?", content: "React es el mejor framework..." }, { slug: "que-es-vue", title: "¿Qué es Vue?", content: "Vue es un framework progresivo..." } ];
B. La Configuración de Rutas
En tu componente principal (App.js), la ruta dinámica le indica a React Router qué componente debe renderizar para cualquier valor que siga a /blog/.
JavaScript
// App.js (Configuración de Rutas) import { BrowserRouter as Router, Route, Routes } from 'react-router-dom'; function App() { return ( <Router> <Routes> {/* Ruta Estática: Muestra la lista de posts */} <Route path="/blog" element={<BlogPage />} /> {/* Ruta Dinámica: Renderiza BlogPost sin importar el valor de :slug */} <Route path="/blog/:slug" element={<BlogPost />} /> </Routes> </Router> ); }
C. El Componente de Detalle (BlogPost)
Este es el componente que se renderiza en todas las rutas dinámicas. Utiliza useParams para volverse inteligente y mostrar solo el contenido pertinente.
JavaScript
// BlogPost.jsx (Componente Dinámico) import { useParams } from 'react-router-dom'; const BlogPost = () => { // 1. Extrae el slug de la URL const { slug } = useParams(); // 2. Usa el slug para encontrar los datos correctos const post = blogData.find(p => p.slug === slug); // 3. Renderiza la información específica return ( <div> <h2>{post.title}</h2> <p>{post.content}</p> </div> ); };
3. Retos y Buenas Prácticas
slug en tu fuente de datos sea único para evitar problemas de duplicidad de URL.slug de la URL no coincide con ningún dato.estoy teniendo una situación que me rompe el coco y no la entiendo, el link del home siempre me queda en rojo, es decir active, así esté en otra página quedan los dos en rojo y le he dado vueltas y no lo entiendo, alguien podrá ayudarme?
Menu component
<import React from 'react' import { NavLink } from 'react-router-dom' const Menu = () => { return ( <nav> <ul> {routes.map(route=>( <li> <NavLink style={({isActive})=>({color: isActive? 'red':'blue'})} to={route.to} >{route.text}</NavLink> </li> ))} </ul> </nav> ) } const routes=[]; routes.push({ to:'/', text:'Home' }); routes.push({ to:'/blog', text:'Blog' }); routes.push({ to:'/profile', text:'Profile' }); export {Menu}>
App component
<import {HashRouter,Routes,Route} from 'react-router-dom' import {Menu} from './Components' import {Home,Blog,Profile,NotFound} from './Pages' function App() { //usamos hash navigation debemos usar /#/endPoint return ( <div className="App"> <HashRouter> <Menu/> <Routes> <Route path='/' element={<Home/>}/> <Route path='/blog' element={<Blog/>}/> <Route path='/profile' element={<Profile/>}/> <Route path='*' element={<NotFound/>}/> </Routes> </HashRouter> </div> ) } export default App>
Hola cayo muchas gracias por la respuesta, lo habí resuelto de la siguiente manera
<<Routepath='/'element={<Home/>} <Routepath='/home'element={<Home/>}> routes.push({ to:'/', text:'Home' });
pero probaré tu respuesta