En Mi aplicación tengo mis rutas definidas, como se muestra a continuación:
<BrowserRouter> <Header /> <div className="App"> <Switch> <Route exact path="/"> <Redirect to="/home" /> </Route> <Route exact path={["/home", "/"]} component={Home} /> <Route path="/account/:id" render={(props: RouteComponentProps<any>) => <Account {...props} />} /> <Route component={NotFound} /> </Switch> </div> </BrowserRouter>Lo que quiero saber es que esto puede ser complicado. Si quisiera que mi ruta tuviera un prefijo de mi contexto, es decir, variable, ¿cómo haría esto, pero el giro es que la variable proviene de una respuesta de API?
Entonces, ¿qué sucede si quisiera la ruta /contextVariable /undefined/home /contextVariable/home pero contextVariable proviene de una respuesta de API y se almacena en un valor de contexto? /undefined/home como en la respuesta, ¿debería terminar antes de insertarse en la ruta?
¿Algunas ideas?
Una vez hice un proyecto que tenía un requisito similar. En eso, en lugar de declarar rutas dinámicas, obtuve una matriz de rutas del estado que era una matriz de objetos con componente, ruta y algunos otros parámetros. De forma predeterminada, agregué la página de destino inicial y la página no encontrada:
const [routes, setRoutes] = React.useState([ { component: HomeComponent, path: '/', }, { component: NoMatchPage, path: '*', } ])Y luego tuve la solicitud en un bloque useEffect que actualizaría este estado así:
React.useEffect(()=>{ // call api() const oldRoutes = routes; const noMatchPage = oldRoutes.pop(); const newRoutes = [...oldRoutes, responseFromApi.map( routeItem => ({ component: ComponentName, path: routeItem.path }) ), noMatchPage] setRoutes(newRoutes) },[])Lo siento, olvidé la parte principal, así es como sería la representación de la ruta:
<Switch> { routes.map(routeItem => <Route path={routeItem.path} component={routeItem.component} /> ) } </Switch>Además, si desea evitar el código adicional en useEffect, simplemente puede hacer esto:
React.useEffect(()=>{ // call api() setRoutes(responseFromApi.map( routeItem => ({ component: ComponentName, path: routeItem.path }) )) },[])y entonces
<Switch> <Route exact path={["/home", "/"]} component={Home} /> { routes.map(routeItem => <Route path={routeItem.path} component={routeItem.component} /> ) } <Route component={NotFound} /> </Switch> En el caso de que el usuario ingrese la URL directamente y Switch no pueda identificar la Route y, por lo tanto, cargue NotFoundPage , puede hacer lo siguiente:
useEffect : const [loading, setLoading] = React.useState(false); React.useEffect(() => { setLoading(true); // load paths setLoading(false); }, [])Loader al usuario: return ( <> { loading ? <LoaderComponent /> : <Switch> // same as before </Switch> } </> )Preferiblemente mostrar algo para que el usuario lea, para que no se irrite, porque la paciencia es cosa del pasado. ¡Espero que esto ayude!
Si desea hacer esto con un React Context, este es el patrón que sugiero. Cree un contexto de reacción que contenga la lógica de la API para obtener una "ruta base" y exponerla a los consumidores. Los consumidores tomarán el valor de "ruta base" proporcionado y lo antepondrán a todos los destinos de enlace y rutas de ruta.
Ejemplo:
BasePathProviderBasePathProvider
import { createContext, useContext } from "react"; const BasePath = createContext({ basepath: "" }); const BasePathProvider = ({ children }) => { ... logic to fetch basepath ... return ( <BasePath.Provider value={{ basepath }}> {children} </BasePath.Provider> ); }; const useBasePath = () => useContext(BasePath);Encabezamiento
const Header = () => { const { basepath } = useBasePath(); return ( ... <Link to={`${basepath}/`}>Home</Link> <Link to={`${basepath}/account/${/* some id value */}`}> Account </Link> ... ); };aplicación
function App() { return ( <div className="App"> <Header /> <BasePath.Consumer> {({ basepath }) => ( <Switch> <Redirect from={`${basepath}/`} exact to={`${basepath}/home`} /> <Route path={`${basepath}/home`} component={Home} /> <Route path={`${basepath}/account/:id`} component={Account} /> <Route component={NotFound} /> </Switch> )} </BasePath.Consumer> </div> ); }índice.js
import { BrowserRouter as Router } from "react-router-dom"; import BasePathProvider from "../path/to/BasePathProvider"; ... <Router> <BasePathProvider> <App /> </BasePathProvider> </Router> Nota: Es posible que también desee/necesite implementar un estado de "carga" para representar condicionalmente los elementos secundarios del componente BasePathProvider hasta children se basepath el valor de la ruta base.