Tengo un conjunto de rutas que se ven así:
{ path: '/things', element: <MainLayout />, children: [ { path: 'search', element: <MainSearch />, }, { path: 'search/:thingId', element: <ThingLayout />, }, { path: '', element: <Navigate to="search" replace />, }, ], }, Donde la idea es buscar algo en MainSearch, obtener resultados, hacer clic en él y acceder a una página /things/search/:thingId para esa Cosa.
Sin embargo, ThingLayout también tiene un paradigma de pestañas, que se establece mediante parámetros de búsqueda y el usuario hace clic en las pestañas dentro de ese componente.
ThingLayout.tsx
import { useParams, useSearchParams } from 'react-router-dom'; const ThingLayout = () => { const [searchParams, setSearchParams] = useSearchParams(); const activeTab = searchParams.get('tab'); // When the user first comes here from general search route, // set the default tab useEffect(() => { if (!activeTab) { setSearchParams({ tab: DEFAULT_TAB }); } }, []); // ... } Mi problema es que necesito (creo) la ruta /search/:thingId para que todas mis rutas /search/:thingId?tab=someTab se resuelvan en este componente, que luego tiene un código para verificar qué pestaña está configurada a través de searchParams y luego represente el componente secundario adecuado, pero si un usuario presiona el botón Atrás, la URL cambia a /search/:thingId y luego vuelve inmediatamente a /search/:thingId?tab=defaultTab . Intenté usar navigate en lugar de setSearchParams para cambiar la URL:
import { useNavigate } from 'react-router-dom'; // ... const navigate = useNavigate(); navigate(`?tab=${DEFAULT_INVENTORY_PARTS_TAB}`) Pero tuve el mismo problema: cuando venía de la búsqueda, primero la URL sería /search/:thingId , luego se convertiría en ?tab=defaultTab .
He buscado en los documentos del enrutador de reacción, así como también he visto muchas preguntas de stackoverflow, y estoy pensando ahora que tal vez solo estoy siguiendo un patrón incorrecto. ¿Mi método de navegación por pestañas es compatible con la forma "correcta" de usar React Router? ¿Cómo puedo combinar la ruta general :id con mi ruta de searchParams de búsqueda manipulada?
La versión de mi enrutador de reacción es "react-router-dom": "^6.2.1"
setSearchParams funciona de manera similar a la función de navigate , pero solo para la URL queryString. Toma un objeto de opciones que es el mismo tipo de argumento que navigate .
declare function useSearchParams( defaultInit?: URLSearchParamsInit ): [URLSearchParams, SetURLSearchParams]; type ParamKeyValuePair = [string, string]; type URLSearchParamsInit = | string | ParamKeyValuePair[] | Record<string, string | string[]> | URLSearchParams; type SetURLSearchParams = ( nextInit?: URLSearchParamsInit, navigateOpts?: : { replace?: boolean; state?: any } ) => void;
Pase un objeto de navigateOpts que establece el tipo de navegación para que sea una redirección.
import { useParams, useSearchParams } from 'react-router-dom'; const ThingLayout = () => { const [searchParams, setSearchParams] = useSearchParams(); const activeTab = searchParams.get('tab'); // When the user first comes here from general search route, // set the default tab useEffect(() => { if (!activeTab) { searchParams.set("tab", DEFAULT_TAB); setSearchParams(searchParams, { replace: true }); } }, []); // ... }La respuesta es usar la función de navigate proporcionada por el useNavigate de react-router-dom , que tiene un parámetro de replace que se le puede pasar, para reemplazar el elemento actual en el historial.
Entonces, mi código que verifica si hay una pestaña seleccionada, y si no, establece el parámetro de búsqueda, ahora navigate a la URL con el conjunto de parámetros de búsqueda adecuado, en lugar de configurar el parámetro de búsqueda directamente y solo.
import { useParams, useSearchParams } from 'react-router-dom'; const ThingLayout = () => { const [searchParams, setSearchParams] = useSearchParams(); const activeTab = searchParams.get('tab'); // When the user first comes here from general search route, // set the default tab useEffect(() => { if (!activeTab) { setSearchParams({ tab: DEFAULT_TAB }); } }, []); // ... }se convierte
import { useSearchParams, useNavigate } from 'react-router-dom'; const ThingLayout = () => { const [searchParams] = useSearchParams(); const navigate = useNavigate(); const activeTab = searchParams.get('tab'); // When the user first comes here from general search route, // set the default tab useEffect(() => { if (!activeTab) { navigate(`?tab=${DEFAULT_TAB}`, {replace: true}); } }, []); // ... }