Los cambios que hice para que funcionará con React router dom versión 5 fueron:
En el archivo App.js
En el archivo TodoForm/index.js
En el archivo HomePage.js
Fundamentos de navegación en la web
Navegación en React Router: Fundamentos y Práctica
Renderizado en el servidor vs aplicaciones de una sola página
React Router DOM 6: Componentes y Navegación Eficiente
Introducción a React Router DOM 6
React Router DOM 6: Instalación y Configuración Básica
Tipos de Routers en React: Browser, Hash y Memory
Rutas Dinámicas con React Router DOM 6
Navegación Dinámica con React Router: Link y NavLink
Rutas dinámicas en React con UseParams y React Router DOM 6
Uso de React Hook useNavigate en React Router DOM 6
Rutas anidadas en React Router DOM: Uso del componente Outlet
Fake authentication con React Router DOM 6
Rutas Protegidas en React: Autenticación y Autorización con Hooks
Navegación Segura con Autenticación en React
Protección de rutas con React Router y Hooks
Autorización y Roles en Aplicaciones Web
Manejo de estado avanzado en React: planetando soluciones efectivas
Redirección post-login con useLocation en React Router DOM
Roles y Permisos en React con Rutas Dinámicas y Autenticación
React Router en TODO Machine
Proyecto React Router: Rutas Dinámicas con Todo Machine
Estructura de Carpetas y Rutas en React con React Router DOM
Maquetación de botones para editar To-Do Items en React
Generación de IDs únicos en JavaScript
Rutas Dinámicas en React: Manejo y Navegación Eficiente
Métodos avanzados para manipular custom hooks en React
Transmisión de Datos en React con useLocation y useState
Proyecto React Router: Desplegando en GitHub Pages
Próximos pasos
Actualización de URL con búsqueda React Router
Retos de Migración en Proyectos React: React Router DOM 5 vs. 6
React.js: Creación de Rutas y Navegación en Aplicaciones Web
Clonación de React Router con Componentes y Hooks
Navegación con React Router DOM: Rutas, Hooks y Autenticación
No tienes acceso a esta clase
¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera
Cuando nos enfrentamos al mundo real de una empresa, no siempre trabajamos con las tecnologías más recientes. Así que, ¿qué ocurre cuando te encuentras con versiones antiguas de ciertas herramientas, como React Router DOM 5, en lugar de las actuales que usaste para tus proyectos personales? La respuesta, según la experiencia compartida, es que debes adaptarte al entorno laboral que encuentres. Es crucial entender que, aunque el aprendizaje y el impulso por estar al día son importantes, muchas empresas aún operan con configuraciones que garantizan estabilidad y continuidad en sus aplicaciones.
Trabajar en un entorno que no siempre está a la vanguardia puede parecer un retroceso, pero tiene su propio valor y lecciones:
En un caso hipotético donde se plantee la migración de React Router DOM de la versión 5 a la 6, la discusión puede centrarse en aspectos prácticos:
Este es un escenario muy común en empresas consolidadas y describe la necesidad de balancear entre innovar y preservar la estabilidad de los productos ya funcionando. Y aunque pueda parecer restrictivo, este tipo de retos nos preparan para enfrentar situaciones similares en entornos laborales reales, donde la adaptabilidad y la habilidad para trabajar con diversas versiones se vuelven cruciales. Por lo tanto, nunca subestimes el valor de dominar versiones anteriores, porque te dota de una perspectiva más amplia y flexible.
Aportes 19
Preguntas 1
Los cambios que hice para que funcionará con React router dom versión 5 fueron:
En el archivo App.js
En el archivo TodoForm/index.js
En el archivo HomePage.js
Hace poco me paso que estaba actualizando esta libreria a la v6 en un proyecto grande. Estaba haciendo todos los cambios hasta que me tope que en la ultima version habian eliminado un feature que estabamos usando para bloquear la navegacion.
Hablo de usePrompt y useBlocker.
Esto se usa si por ejemplo el usuario esta completando un formulario y antes de guardar los cambios quiere navegar a otra ruta. Nosotros le mostramos un modal de confirmacion antes de hacer la navegacion si tiene cambios. Entonces usamos ese feature. Pero en la version 6 no se puede (o no descubri como) hacerlo.
Aquí les dejo la documentación de react-router v5 😎👇
Hecho! Este me parece uno de los mejores retos del curso, sin él nunca me hubiera probado una versión anterior de nada.
.
La mayoría de cambios son superficiales, cambian las rutas y algunos hooks por otros. Me voy a explayar en el reto de los query params, que sí es más complicado.
.
Anteriormente, se podía usar el hook useSearchParams. Lamentablemente este no está en la V5. Lo que hice después de muuuucha investigación fue hacer un hook propio (fuertemente inspirado en respuestas de StackOverflow)
.
import { useMemo } from 'react'
import { useLocation } from 'react-router-dom'
export function useQuery(value) {
const { search } = useLocation()
const setQuery = useMemo(() => new URLSearchParams(search), [search])
const query = setQuery.get(value)
return [query, setQuery]
}
Luego lo implementé de la siguiente manera:
import React from 'react'
import { useEffect } from 'react'
import { useHistory } from 'react-router-dom'
import { useQuery } from '../hooks/useQuery'
export function TodoSearch({ setSearchValue, searchValue, loading }) {
const [searchQuery] = useQuery('search')
const history = useHistory()
const onSearchValueChange = ({ target: { value } }) => {
setSearchValue(value)
history.push({ search: `search=${value}` })
}
useEffect(() => {
if (searchQuery && searchQuery !== searchValue)
setSearchValue(searchQuery)
}, [searchQuery, setSearchValue, searchValue])
return (
<input
className={`TodoSearch ${loading && 'TodoSearch--loading'}`}
onChange={onSearchValueChange}
value={searchQuery ?? ''}
placeholder="Search a To-Do"
/>
)
}
Se siente tan fácil una vez terminado… no fue directo, pero fue muy entretenido y un gran desafío.
React Router V5 vs V6 dev.to
Documentación de React Router reactrouter.com
No fue tan sencillo como parece… Batalle mucho con el reto de TodoSearch.
Dejo el codigo por si a alguien le sirve de apoyo.
function TodoSearch({ searchValue, setSearchValue, loading }) {
const history = useHistory();
const onSearchValueChange = (event) => {
const value = event.target.value;
setSearchValue(value);
history.push({ search: value });
//modificar la url y guarda todo en location
};
const param = history.location.search.slice(1);
// usar el metodo slice para quitar '?' al inicio del string
const searchParam = decodeURI(param) ?? searchValue;
// decodeURI es una funcion de javascript ayuda a decodificar la url.
return (
<input
className="TodoSearch"
placeholder="Cebolla"
value={searchParam}
onChange={onSearchValueChange}
disabled={loading}
/>
);
}
Lo único raro, fue switch en vez de routes y route.
.
El reto es replicar el mismo comportamiento de la aplicación con React Router DOM 5.
.
Para ello vamos a mantener la misma estructura de carpetas que utilizamos para la aplicación con React Router DOM 6 pero modificando algunos archivos donde algunos hooks o componentes proporcionados por este no existan o funcionen distintamente en la versión 5.
.
Para este reto hemos utilizado la versión 5.3.4
de React Router DOM.
.
"react-router-dom": "^5.3.4"
.
En src/routes/App.js
ya no se usa el componente Routes
de la versión 6, sino que se usa Switch
. En lugar de element
para definir el componente que se debe renderizar ahora utilizamos component
.
.
Otra diferencia es que en la versión 6 element
acepta un elemento de React directamente como <HomePage />
, mientras que en la versión 5 component
solo acepta una referencia a un componente como HomePage
.
.
En la versión 6, es más directo usar el prop element={<p>Not Found</p>}
con JSX, mientras que en la versión 5, se utiliza una función que retorna JSX component={() => <p>Not Found</p>}
.
.
en la versión 6 Routes
entiende de forma implícita cuándo una ruta es exacta, no se usa exact
porque el enrutador lo maneja automáticamente, mientras que en la versión 5 usa exact
para asegurar que la ruta exacta se corresponda.
.
import React from "react";
import { HashRouter, Route, Switch } from "react-router-dom";
import { EditTodoPage } from "./edit/EditTodoPage";
import { HomePage } from "./home/HomePage";
import { NewTodoPage } from "./new/NewTodoPage";
function App() {
return (
<HashRouter>
<Switch>
<Route exact path="/" component={HomePage} />
<Route path="/new" component={NewTodoPage} />
<Route path="/edit/:id" component={EditTodoPage} />
<Route path="*" component={() => <p>Not Found</p>} />
</Switch>
</HashRouter>
);
}
export { App };
.
En el componente HomePage
, vamos a remplazar useNavigate
por useHistory
para la navegación con React Router DOM 5. El hook useHistory
utiliza un método push
para navegar a una ruta.
.
Ambas versiones permiten pasar un estado a través de la navegación, en la versión 6 con navigate('/edit/' + todo.id, { state: { todo } })
y en la versión 5 con history.push('/edit/' + todo.id, { todo })
.
.
import React from "react";
import { useHistory } from "react-router-dom";
import { useTodos } from "../useTodos";
import { TodoHeader } from "../../ui/TodoHeader";
import { TodoCounter } from "../../ui/TodoCounter";
import { TodoSearch } from "../../ui/TodoSearch";
import { TodoList } from "../../ui/TodoList";
import { TodoItem } from "../../ui/TodoItem";
import { TodosError } from "../../ui/TodosError";
import { TodosLoading } from "../../ui/TodosLoading";
import { EmptyTodos } from "../../ui/EmptyTodos";
import { CreateTodoButton } from "../../ui/CreateTodoButton";
import { ChangeAlert } from "../../ui/ChangeAlert";
function HomePage() {
const history = useHistory();
const { state, stateUpdaters } = useTodos();
const {
error,
loading,
searchedTodos,
totalTodos,
completedTodos,
searchValue,
} = state;
const {
completeTodo,
deleteTodo,
setSearchValue,
sincronizeTodos,
} = stateUpdaters;
return (
<React.Fragment>
<TodoHeader loading={loading}>
<TodoCounter totalTodos={totalTodos} completedTodos={completedTodos} />
<TodoSearch searchValue={searchValue} setSearchValue={setSearchValue} />
</TodoHeader>
<TodoList
error={error}
loading={loading}
totalTodos={totalTodos}
searchedTodos={searchedTodos}
searchText={searchValue}
onError={() => <TodosError />}
onLoading={() => <TodosLoading />}
onEmptyTodos={() => <EmptyTodos />}
onEmptySearchResults={(searchText) => (
<p>No hay resultados para {searchText}</p>
)}
>
{(todo) => (
<TodoItem
key={todo.id}
text={todo.text}
completed={todo.completed}
onEdit={() => {
history.push("/edit/" + todo.id, { todo });
}}
onComplete={() => completeTodo(todo.id)}
onDelete={() => deleteTodo(todo.id)}
/>
)}
</TodoList>
<CreateTodoButton
onClick={() => history.push("/new")}
// setOpenModal={setOpenModal}
/>
<ChangeAlert sincronize={sincronizeTodos} />
</React.Fragment>
);
}
export { HomePage };
.
En TodoForm
es hacer lo mismo, remplazar useNavigate
por useHistory
.
.
import React from 'react';
import { useHistory } from 'react-router-dom';
import './TodoForm.css';
function TodoForm(props) {
const history = useHistory();
const [newTodoValue, setNewTodoValue] = React.useState(props.defaultTodoText || '');
const onChange = (event) => {
setNewTodoValue(event.target.value);
};
const onCancel = () => {
history.push('/');
};
const onSubmit = (event) => {
event.preventDefault();
props.submitEvent(newTodoValue);
history.push('/');
};
return (
<form onSubmit={onSubmit}>
<label>{props.label}</label>
<textarea
value={newTodoValue}
onChange={onChange}
placeholder="Cortar la cebolla oara el almuerzo"
/>
<div className="TodoForm-buttonContainer">
<button
type="button"
className="TodoForm-button TodoForm-button--cancel"
onClick={onCancel}
>
Cancelar
</button>
<button
type="submit"
className="TodoForm-button TodoForm-button--add"
>
{props.submitText}
</button>
</div>
</form>
);
}
export { TodoForm };
.
Finalmente, en TodoSearch
es donde se dio el mayor cambio, puesto que habíamos implementado búsqueda por navegación con useSearchParams
. Sin embargo, este hook no existe en la versión 5 de React Router DOM.
.
Lo que se hizo fue utilizar useHistory
y useLocation
para obtener la propiedad search
de useLocation
, luego cada que escribamos algo en el input de búsqueda vamos a navegar con useHistory
hacia el pathname /
con ?search=${event.target.value}
concatenado con lo que escribamos en dicho input.
.
Finalmente, en un useEffect
revisamos que si el search
empieza con ?search=
significa que hemos accedido directamente a la búsqueda por la url, así que recuperamos el valor de la búsqueda, lo decodificamos en caso de que la búsqueda contuviera espacios representados como %20
y cambiamos el estado de searchValue
mediante setSearchValue
.
.
De esta manera obtendremos la búsqueda por navegación tanto por el input de búsqueda, como desde la url.
.
import React, { useEffect } from "react";
import "./TodoSearch.css";
import { useHistory, useLocation } from "react-router-dom";
function TodoSearch({ searchValue, setSearchValue, loading }) {
const { search } = useLocation();
const history = useHistory();
const onSearchValueChange = (event) => {
setSearchValue(event.target.value);
history.push({
pathname: "/",
search: `?search=${event.target.value}`,
});
};
useEffect(() => {
if (search.startsWith("?search=")) {
setSearchValue(decodeURIComponent(search.substring(8)));
}
}, [searchValue]);
return (
<input
className="TodoSearch"
placeholder="Cebolla"
value={searchValue}
onChange={onSearchValueChange}
disabled={loading}
/>
);
}
export { TodoSearch };
Aquí les comparto mi repositorio en github en donde la rama main está con react router dom v6, mientras que la rama proyecto-react-router-dom-5, la aplicación está con react router dom v5.
Repositorio:
curso-react-router-proyecto2
tuve unos errores orribles, los cuales no pude salir, aquí les muestro cuales eran
Tenia todos los imports que se necesitaban pero me seguian pasando los errores, como por ejemplo el primero que me dice que en ese archivo index de el folder TodoForm no encuentra el useHistory donde si lo estoy importando
Oigaan.
Lo logre. Utilizando
Switch, useHistory y useLocation de la V5
Pero el input de search porque cuando quiero escribir me queda invalido hasta que hago click?
por cada letra que quiero colocar es un click que debo hacer al input
¿Quieres ver más aportes, preguntas y respuestas de la comunidad?