简体   繁体   English

React Router V5 在路由中使用上下文变量的最佳方式

[英]React Router V5 best way to use context variable in route

In My app I have my routes defined, as per below:在我的应用程序中,我定义了我的路线,如下所示:

        <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>

What I want to know is, this can be tricky, If I wanted my route to have a prefix from my context ie variable how would I do this, but the twist is the variable comes from an api response?我想知道的是,这可能很棘手,如果我希望我的路线有一个来自我的上下文的前缀,即变量,我将如何做到这一点,但扭曲的是变量来自 api 响应?

so what if i wanted the route /contextVariable/home but contextVariable is from an api response and is stored in a context value, I know how I would bring that variable into the component but how would the routes handle it ie from not being /undefined/home as in the response would need to finish before being inserted into the route?那么如果我想要路由/contextVariable/homecontextVariable来自 api 响应并存储在上下文值中,我知道如何将该变量带入组件但路由将如何处理它,即不是/undefined/home作为响应是否需要在插入路由之前完成?

Any idea's?有任何想法吗?

I had once made a project that had similar requirement.我曾经做过一个有类似要求的项目。 In that, instead of declaring dynamic routes, I fetched a routes array from the state which was an object array with component, path, and few other parameters.在那里,我没有声明动态路由,而是从 state 获取了一个路由数组,该数组是一个 object 数组,包含组件、路径和一些其他参数。 By default I added the initial landing page and not found page:默认情况下,我添加了初始登录页面和未找到页面:

const [routes, setRoutes] = React.useState([
{
 component: HomeComponent,
 path: '/',
},
{
 component: NoMatchPage,
 path: '*',
}
])

And then I had the request in a useEffect block which would update this state like so:然后我在 useEffect 块中有请求,它将像这样更新这个 state:

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)
},[])

Edit编辑

Sorry, I forgot the main part, here's how the Route rendering would be:抱歉,我忘记了主要部分,这是 Route 渲染的方式:

<Switch>
    {
      routes.map(routeItem =>
        <Route path={routeItem.path} component={routeItem.component} />
      )
    }
</Switch>

Also if you want to avoid the extra code in useEffect, you could simply do this:此外,如果您想避免 useEffect 中的额外代码,您可以简单地执行以下操作:

React.useEffect(()=>{
 // call api()
 setRoutes(responseFromApi.map(
     routeItem => 
        ({
          component: ComponentName, 
          path: routeItem.path
        })
     ))
},[])

and then接着

<Switch>
    <Route exact path={["/home", "/"]} component={Home} />
    {
      routes.map(routeItem =>
        <Route path={routeItem.path} component={routeItem.component} />
      )
    }
    <Route component={NotFound} />
</Switch>

If you want to do this with a React Context then this is the pattern I'd suggest.如果您想使用 React Context 执行此操作,那么这是我建议的模式。 Create a React Context that holds the API logic to fetch a "base path" and expose that out to consumers.创建一个包含 API 逻辑的 React 上下文,以获取“基本路径”并将其公开给消费者。 Consumers will take the provided "base path" value and prepend it to all link targets and route paths.消费者将采用提供的“基本路径”值并将其添加到所有链接目标和路由路径。

Example:例子:

BasePathProvider BasePathProvider

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);

Header Header

const Header = () => {
  const { basepath } = useBasePath();

  return (
    ...
    <Link to={`${basepath}/`}>Home</Link>
    <Link to={`${basepath}/account/${/* some id value */}`}>
      Account
    </Link>
    ...
  );
};

App应用程序

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>
  );
}

index.js index.js

import { BrowserRouter as Router } from "react-router-dom";
import BasePathProvider from "../path/to/BasePathProvider";

...

<Router>
  <BasePathProvider>
    <App />
  </BasePathProvider>
</Router>

编辑 react-router-v5-best-way-to-use-context-variable-in-route

Note: You might also want/need to implement a "loading" state to conditionally render the BasePathProvider component's children until the basepath value has been fetched.注意:您可能还希望/需要实现“加载” state 以有条件地渲染BasePathProvider组件的children组件,直到获取基本basepath值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM