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

IT技术 javascript reactjs react-router react-router-dom
2022-07-19 01:59:58

在我的应用程序中,我定义了我的路线,如下所示:

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

我想知道的是,这可能很棘手,如果我希望我的路线有一个来自我的上下文的前缀,即变量,我将如何做到这一点,但扭曲的是变量来自 api 响应?

那么,如果我想要路由/contextVariable/homecontextVariable来自 api 响应并存储在上下文值中,我知道如何将该变量带入组件,但路由将如何处理它,即不会/undefined/home像响应中那样需要在插入路线之前完成?

有任何想法吗?

2个回答

我曾经做过一个有类似要求的项目。在那里,我没有声明动态路由,而是从 state 中获取了一个 routes 数组,它是一个包含组件、路径和一些其他参数的对象数组。默认情况下,我添加了初始登录页面和未找到页面:

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

然后我在 useEffect 块中有请求,它将像这样更新此状态:

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

编辑1:因为我健忘

抱歉,我忘记了主要部分,这是 Route 渲染的方式:

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

此外,如果您想避免 useEffect 中的额外代码,您可以简单地执行以下操作:

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

接着

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

编辑2:因为我无知

如果用户直接输入 URL 并且Switch无法识别Route并因此加载NotFoundPage,您可以执行以下操作:

  1. 在块内开始加载路径时设置条件useEffect
const [loading, setLoading] = React.useState(false);
React.useEffect(() =>
    {
      setLoading(true);
      // load paths
      setLoading(false);
    }, [])
  1. 在获取过程中,Loader向用户显示:
return
    (
    <>
        {
           loading ? 
             <LoaderComponent /> : 
             <Switch>
                // same as before
             </Switch>
        }
    </>
    )

最好显示一些内容供用户阅读,这样他们就不会生气,因为耐心已成为过去。希望这可以帮助!

如果您想使用 React Context 执行此操作,那么这是我建议的模式。创建一个包含 API 逻辑的 React 上下文,以获取“基本路径”并将其公开给消费者。消费者将采用提供的“基本路径”值并将其添加到所有链接目标和路由路径。

例子:

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

标题

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

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

应用程序

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

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

注意:您可能还希望/需要实现“加载”状态以有条件地渲染BasePathProvider组件children,直到basepath获取该值。