Rutas como Componentes

Usar React Router DOM para controlar la navegación

Dragon Nomada
React Adventure
7 min readFeb 25, 2021

--

Se muestra un barco de papel, como referencia a la navegación. Tomada de https://unsplash.com/photos/sRg9N_0pn1Q

Realizar navegación en la aplicación, es tan sencillo como entender la documentación de React Router DOM. La navegación consiste en definir rutas, para que un componente sea visualizado al dirigirse a la ruta en el navegador. También podemos navegar entre rutas, a través de enlaces y hooks, para enviarle un estado asociado al componente navegado.

Gracias a librería react-router-dom, podemos crear rutas fijas, por ejemplo, para mostrar formularios, listas o tablas de datos, entre otros. También podemos crear rutas dinámicas, para mostrar los datos de un cliente específico, un producto identificado, alguna orden o contrato, etc.

Crear el contexto Router

Lo primero es crear un contexto, usando el proveedor BrowserRouter asignado como Router simplemente. Para permitir aislar la navegación y sus rutas.

Sintaxis

Donde <Router> es el proveedor del sistema de router, en realidad es equivalente a usar directamente <BrowserRouter>, existen además <HashRouter> y <MemoryRouter> con diferencias en la estructuración de la ruta sobre el navegador.

El primero de los ruteadores BrowserRouter es la ruta explícita como parte del path como /demo, el segundo HashRouter usa los hashes como #/demo sin interferir con el path, y el último MemoryRouter lo hace en memoria, útil en situaciones dónde tengamos navegaciones en regiones locales, como popus o modales.

Todos lo Links, Rutas y Componentes dentro del Router, estarán bajo este contexto de navegación, por lo que podremos usar los hooks, para recuperar el history , y hacer navegación, el location, para consultar la ruta actual, params, para recuperar los parámetros de navegación dinámicos, y el match, para acceder igualmente a datos sobre la url.

Definir Rutas con Switch y Route

Para definir una ruta, es decir, lo que se verá al dirigirnos a la ruta, debemos colocar el componente Switch y dentro de él, un componente Route por cada ruta.

Sintaxis

Donde <Switch> provee el contexto dónde serán definidas las rutas definidas. Y <Route> cada ruta definida con su interfaz.

Alternativamente, si la ruta está basada en un único componente, podemos usar <Route path="/my-path" component={MyComponent} />, para que el se encargue de montar nuestro componente, en este caso, nuestro componente recibirá el history, location, match y demás objetos de navegación, como propiedades. En lo personal, no lo recomiendo, ya que, aunque podría ser más optimo en algunos casos, también es más abstracto, aumentando el mantenimiento a largo plazo.

Adeventencia: Las rutas definidas mediante Route, están dentro del componente Switch, que tomará la primera ruta que coincida con el pathname al que se desea navegar. Debemos tener cuidado de definir primero las rutas más específicas, y al final, las rutas más genéricas, para evitar que una ruta, atrape a otra. Por ejemplo, si primero definimos la ruta /foo, y luego la ruta /foo/bar, entonces, nunca podrémos acceder a la ruta /foo/bar, ya que siempre coincidirá la ruta /foo, es decir, cuándo navegamos a /foo/bar/zip/..., tomará la primer ruta definida que coincida, evitando las siguientes, es por eso, que la primer ruta definida dentro de Switch, debe ser la más específica, luego una menos específica, y así sucesivamente.

Navegar a las rutas mediante Link

La forma más sencilla de realizar la navegación, es usar el componente Link, para de este modo dirigirnos a la ruta. Esto es lo recomendado versus usar el componente tradicional <a href="/my-path">, ya que este último recargará la página. Además, no podremos enviar un estado de navegación, y demás parámetros interesantes.

Sintaxis

Donde <Link> es el componente similar a <a> que actúa como enlace de navegación, hacia el pathname definido en la propiedad to="/my-path".

Observa que en el segundo caso, podemos definir un objeto de navegación, incrementando las posibilidades, como el estado de navegación, que será pasado.

El hook de navegación — useHistory

El hook useHistory, permite acceder al objeto history, que posee varios métodos para navegar, y acceso al objeto location igualmente. Algunos de los métodos más importantes son push(pathname, state), que nos dirige a una ruta, con un estado opcional asociado, y replace(pathname, state), que funciona similar, sólo que reemplazando la ruta y sobre el historial de navegación. Los métodos goBack() y goForward(), que nos permitirán navegar hacia atrás y hacia adelante.

Sintaxis

Donde history es un objeto con los métodos push, replace, goBack, goForward, entre otros. También podemos acceder a history.location, para obtener información de la ruta.

El hook de ruta — useLocation

El hook useLocation, permite acceder al objeto location. Este objeto nos permitirá acceder a los atributos de la ruta, como es pathname, que es la ruta actual, search que es el query asociado a la ruta del tipo ?foo=bar, el hash de la ruta del tipo #foo-bar, y el estado de navegación pasado a la ruta, sólo si la navegación se hizo con dicho estado, sino, será undefined.

Sintaxis

Donde location es un objeto que contiene los atributos de pathname, search, hash y state. Con los cuales podrémos consultar todo lo referente a la ruta.

El hook de rutas dinámicas — useParams

El hook useParams, permite acceder un objeto que retiene cada parámetro dinámico ajustado sobre la ruta. Cuándo se especifica una ruta, esta puede contener parámetros de la forma :foo o :bar, referentes a parámetros dinámicos, que adquirirán el valor que establezca el usuario, sobre la url. Por ejemplo, la ruta /clients/client/:id, podrá acceder al parámetro id que contenga el valor dado por el usuario, como, /clients/client/c018, referente al usuario c018, o si se accede a la ruta /clients/client/d970, ahora el parámetro id tomará el valor de d970. Estos parámetros son útiles para recuperar valores colocados sobre el pathname de la ruta, de tal forma que nos genera una ruta dinámica y rica en información.

Por ejemplo, la ruta /facturas/:uuid/proveedores/:pid, nos permitirá acceder a dos parámetros dinámicos sobre la url, que son uuid y pid, de tal modo, que podremos consultar los datos del proveedor de una factura, conociendo el uuid de la factura y el id del proveedor.

Sintaxis

Donde params es un objeto que tendrá como atributos, cada parámetro sobre la ruta especificada mediante :, como en /demo/:id, tendremos { id: "1" } o { id: "ABC" }, según sea el caso.

Manos a la obra — Proyecto Todo Routes

En el siguiente proyecto, vamos a construir una interfaz para retener tareas por hacer, en la ruta principal, mostraremos un botón para agregar una nueva tarea, el cuál al pulsarlo, nos mandará a la ruta para agregar un nuevo todo, mediante un formulario. También en la ruta principal, mostraremos una lista con las tareas agregadas, cada una con un enlace de ver detalles, que nos mandará a la ruta de detalles y un enlace de editar, que nos mandará a la ruta para editar la tarea y guardarla. Usaremos un contexto y un hook personalizado, para simplificar la lógica. Por razones didácticas, no separaremos el código en diferentes archivos, para mantener la visión general de todo lo que se está haciendo.

Revisa cuidadosamente el código, y observa, la definición del contexto TodoContext, el hook useTodoApi, el proveedor TodoProvider que provee a todoApi, los diferentes componentes para agregar TodoAdd, ver TodoView y editar TodoEdit, los componentes intermedios TodoItem y TodoList.

Observa que todas las operaciones para agregar, editar y demás, quedan bajo la interfaz de programación de nuestro hook personalizado useTodoApi. Como se ve en el artículo Hooks como Interfaces de programación, y también el uso de contextos, explicado en Contextos como Proveedores.

Conclusiones

Hemos visto como crear un sistema de ruteo, para mostrar diferentes componentes según la ruta conocida como el pathname. Mediante el componente BrowserRouter hemos creado el contexto de ruteo, mediante el componente Switch y Route hemos definido los componentes que serán mostrados en cada ruta, mediante Link hemos podido navegar a una ruta, e incluso enviar un estado de navegación, y mediante los hooks useHistory, useLocation y useParams hemos accedido a métodos y valores de navegación.

La librería react-router-dom es muy útil y ponente para realizar navegación entre componentes, los cuáles a través de hooks fáciles de usuar, podemos implementar diversas formas de navegación entre componentes, enviando valores como parámetros o estados. Además, la documentación de está librería, disponible en https://reactrouter.com es bastante completa y fácil de entender.

Debemos entender que cuándo deseemos implementar un sistema de navegación, lo primero es determinar que tipo de sistema de ruteo queremos, si la navegación física del navegador usando BrowserRouter, una navegación de ruta fija con hash variable usando HashRouter, una navegación en memoria con MemoryRouter o demás estilos como estáticas y demás que encontraremos en la documentación. Lo siguiente, será definir cada ruta en nuestro Switch y determinar el componente o los componentes que se mostrarán bajo la ruta mediante Route. Esto nos permitirá darle riqueza a nuestra aplicación, y atacar problemáticas comunes como las de la siguiente lista.

  1. Definir una ruta que muestre una lista o tabla de datos.
  2. Definir una ruta que muestre un formulario para agregar nuevos datos a la lista o tabla.
  3. Definir una ruta que detalle un elemento de la lista o tabla de datos.
  4. Definir una ruta que edite un elemento de la lista o tabla
  5. Definir una ruta que muestre los datos públicos de un elemento de la lista, recibiendo los parámetros desde la url, como el identificador y token de acceso.
  6. Definir rutas seguras que requieran un token de acceso provisto sobre la url o bajo el estado de navegación.

Así, podremos ir extendiendo la lista anterior, con problemáticas comunes entre una aplicación y otra, para ir consolidando hooks y demás componentes reutilizables de un proyecto a otro.

--

--

Dragon Nomada
React Adventure

I love maths, algorithms, artificial intelligence, data science and zen's philosophy