Saltearse al contenido

RouterProvider (MichiProvider)

Es el Proveedor principal del enrutador. Por motivos felinos, se recomienda importar este componente como: import { RouterProvider as MichiProvider } from '@arielgonzaguer/michi-router';.

Toma dos props y un children:

  • routes: Array<{ path: string; component: React.ReactNode; }> → Array de rutas disponibles
  • layout: React.ComponentType → Componente de layout opcional para envolver todas las rutas
  • children: React.ReactNode → Contenido a mostrar cuando no hay coincidencia de ruta (404)
const getCurrentPath = () => {
return window.location.pathname;
};
export function RouterProvider({
routes,
children,
layout: Layout,
}: RouterProviderProps) {
const [path, setPath] = useState(getCurrentPath());
useEffect(() => {
const handlePopState = () => setPath(window.location.pathname);
window.addEventListener("popstate", handlePopState);
return () => window.removeEventListener("popstate", handlePopState);
}, []);
const navigate = useCallback((to: string) => {
if (!isBrowser) {
setPath(to);
return;
}
// Validación básica de la URL para prevenir navegación a URLs maliciosas
if (
typeof to !== "string" ||
to.includes("javascript:") ||
to.includes("data:")
) {
console.warn("MichiRouter: URL potencialmente insegura bloqueada:", to);
return;
}
window.history.pushState({}, "", to);
setPath(to);
}, []);
// Encontrar la ruta actual
const currentRoute = routes.find((route) => route.path === path);
const routeContent = currentRoute ? currentRoute.component : children;
try {
return (
<RouterContext.Provider value={{ path, navigate }}>
{Layout ? <Layout>{routeContent}</Layout> : routeContent}
</RouterContext.Provider>
);
} catch (error) {
console.error("Error en RouterProvider:", error);
return (
<div>Error en el enrutador. Consulta la consola para más detalles.</div>
);
}
}

Ejemplo de uso:

MichiRouter.tsx
// enrutado
import {
RouterProvider as MichiProvider,
Protected,
} from "@arielgonzaguer/michi-router";
// componentes / páginas
import Landing from "../pages/Landing";
import LoginPage from "../pages/LoginPage";
import ResetContraseña from "./ResetContraseña";
import Home from "../pages/Home";
import NotFound404 from "../components/NotFound404";
import ActualizarKegs from "../pages/ActualizarKegs";
import VerKegInfoScan from "./VerKegInfoScan";
import Configuracion from "../pages/Configuracion";
// layout
import BaseLayout from "../layouts/BaseLayout";
// store que maneja autenticación → para Protected
import useAuthStore from "../store/useAuthStore";
// componente de enrutado
export function MichiRouter() {
// objeto de configuración para Protected
const configObject = {
states: useAuthStore(),
redirectionPath: "/",
loadingComponent: (
<div className="w-full h-screen flex items-center justify-center">
Cargando...
</div>
),
defaultMessage: false,
};
const rutas = [
{ path: "/", component: <Landing /> },
{ path: "/login", component: <LoginPage /> },
{ path: "/reset-password", component: <ResetContraseña /> },
{
path: "/home",
component: (
<Protected configObject={configObject}>
<Home />
</Protected>
),
},
{
path: "/actualizar-kegs",
component: (
<Protected configObject={configObject}>
<ActualizarKegs />
</Protected>
),
},
{
path: "/ver-kegs-scan",
component: (
<Protected configObject={configObject}>
<VerKegInfoScan />
</Protected>
),
},
{
path: "/configuracion",
component: (
<Protected configObject={configObject}>
<Configuracion />
</Protected>
),
},
];
return (
<RouterProvider routes={rutas} layout={BaseLayout}>
<NotFound404 />
</RouterProvider>
);
}
// componente raíz de la app
// este componente suele ser App.tsx
import MichiRouter from "./componentes/MichiRouter";
export default function App() {
return <MichiRouter />;
}

RouterProvider incluye varias medidas de seguridad integradas:

El router bloquea automáticamente URLs potencialmente peligrosas:

// ❌ Estas URLs son bloqueadas automáticamente
navigate('javascript:alert("XSS")');
navigate('data:text/html,<script>alert("XSS")</script>');
// ✅ Estas URLs son permitidas
navigate("/dashboard");
navigate("/user/123");
navigate("https://external-site.com");

🔔

Las rutas para MichiProvider y objeto de configuración para Protected usan hooks, por lo que deben estar dentro de un componente React.