Navegación en React: no solo un clic en un enlace
\n\n¿Alguna vez se ha preguntado cómo hacer que React Router navegue a otra página no por un clic del usuario, sino por una orden desde el código? Por ejemplo, después de enviar un formulario con éxito, una autenticación o simplemente después de 5 segundos? Si es así, ha llegado al lugar indicado. La pregunta "How can I programmatically navigate using React Router?" es una de las más populares en Stack Overflow, y no es casualidad. Parece sencillo, pero en realidad esconde muchas trampas, especialmente cuando se trata del rendimiento.
\n\nEn este artículo no solo mostraremos cómo usar useNavigate. Analizaremos cómo hacerlo correctamente, de forma rápida y sin retrasos. Descubrirá qué patrones provocan fugas de memoria y cuáles conducen a una navegación ultrarrápida. ¡Allá vamos!
Lo clásico: useNavigate — su herramienta principal
\n\nA partir de React Router v6, useNavigate reemplazó al antiguo useHistory. Este es un hook que devuelve la función navigate. Se ve así:
import { useNavigate } from 'react-router-dom';\n\nfunction LoginButton() {\n const navigate = useNavigate();\n\n const handleLogin = () => {\n // Aquí la lógica de autenticación\n const user = { name: 'Iván' };\n // Después del éxito — redirección\n navigate('/dashboard', { replace: true });\n };\n\n return <button onClick={handleLogin}>Iniciar sesión</button>;\n}\n\n\nObserve el parámetro { replace: true }. Este reemplaza la entrada actual en el historial, no añade una nueva. Esto es crítico para el inicio de sesión, para que el usuario no pueda volver atrás a la página de inicio de sesión.
¿A dónde se puede navegar?
\n- \n
- Ruta absoluta:
navigate('/about')\n - Ruta relativa:
navigate('../settings')\n - Atrás/adelante en el historial:
navigate(-1)onavigate(2)\n
Nivel avanzado: navegación fuera de los componentes
\n\n¿Y si necesita hacer una redirección desde una función normal, no dentro de un componente de React? Por ejemplo, desde un action creator en Redux o desde un interceptor de axios? El hook useNavigate no funcionará aquí — los hooks solo se invocan dentro de componentes funcionales.
Solución: crear un componente envoltorio personalizado o usar un objeto enrutador global. En React Router v6 existe el componente especial RouterProvider y createBrowserRouter, pero también hay una forma más simple: guardar una referencia a navigate en una variable.
// router.js\nimport { createBrowserRouter, RouterProvider } from 'react-router-dom';\n\nexport const router = createBrowserRouter([...]);\n\n// navigation.js — módulo separado para la navegación\nlet navigateFunction = null;\n\nexport const setNavigate = (navigate) => {\n navigateFunction = navigate;\n};\n\nexport const navigateTo = (path) => {\n if (navigateFunction) {\n navigateFunction(path);\n } else {\n console.warn('La navegación aún no está lista');\n }\n};\n\n// App.js\nimport { useNavigate } from 'react-router-dom';\nimport { setNavigate } from './navigation';\nimport { useEffect } from 'react';\n\nfunction App() {\n const navigate = useNavigate();\n\n useEffect(() => {\n setNavigate(navigate);\n }, [navigate]);\n\n return /* su código */;\n}\n\n\nAhora desde cualquier función (ya sea desde setTimeout o desde fetch) puede llamar a navigateTo('/home'). ¿Cómodo? Sí. ¿Seguro? Solo si no olvida limpiar la referencia al desmontar el componente.
Optimización del rendimiento: ¿por qué su aplicación se ralentiza?
\n\nLa navegación programática no es solo una llamada a una función. Es un desencadenante para un rerenderizado completo de la página. Y si hace esto