我正在阅读React Router 中的静态与动态路由,我正在努力确定后者的优势(以及为什么 v4 选择使用它)。我可以看到列出应用程序的所有路由(静态)以及每个路由映射到的组件的优势,允许您跟踪给定特定 URL 将呈现的内容。但我没有看到动态路线有任何明显的优势。
如果有的话,我只能看到缺点,因为没有明确的方法来查看 URL 将映射到什么状态,而不是从根应用程序元素开始并通过路由(尽管我可能弄错了)。
动态路由解决什么情况?为什么它比静态路由更可取(可能特别是在 React 应用程序中)?
我正在阅读React Router 中的静态与动态路由,我正在努力确定后者的优势(以及为什么 v4 选择使用它)。我可以看到列出应用程序的所有路由(静态)以及每个路由映射到的组件的优势,允许您跟踪给定特定 URL 将呈现的内容。但我没有看到动态路线有任何明显的优势。
如果有的话,我只能看到缺点,因为没有明确的方法来查看 URL 将映射到什么状态,而不是从根应用程序元素开始并通过路由(尽管我可能弄错了)。
动态路由解决什么情况?为什么它比静态路由更可取(可能特别是在 React 应用程序中)?
从反应路由器文档:
当我们说动态路由时,我们指的是在您的应用程序渲染时发生的路由 ,而不是在正在运行的应用程序之外的配置或约定中。
react-router(pre v4)的早期版本曾经有静态路由。这导致了应用程序中的集中路由,例如:
<Router>
<Route path='/' component={Main}>
<IndexRoute component={Home} />
<Route path='about' component={About} />
<Route onEnter={verifyUser} path='profile' component={Profile} />
...
</Route>
</Router>
然而,这并不完全是React的做事方式。React 专注于使用基于组件的逻辑进行组合。因此,与其将我们的 Routes 想象为一个静态系统,我们可以将它们想象为组件,这就是 react-router v4 带来的内容以及它背后的主要理念。
因此,我们可以Route像使用任何 React 组件一样使用。这让我们可以Route在构建不同组件时添加组件。这样做的一个好处是我们可以将路由逻辑与需要它们的组件解耦。
该About组件可以处理所有路由并根据 url(比如等)有条件地渲染 UI 的/about/job一部分/about/life。
另一件需要注意的事情是,一个Route组件要么为匹配的路由渲染该组件,要么为null. 例如,以下Route渲染About路由的组件,/about否则null(或不渲染)。
<Route path='about' component={About} />
这也类似于我们在 React 中用于有条件地渲染组件的方式:
route === '/about' ? <About /> : null
现在,如果我们需要在组件内部About为路由渲染一些其他组件,/about/job或者/about/life我们可以这样做:
const About = ({ match ) => (
<div>
...
<Route path={`${match.url}/job`} component={Job} />
<Route path={`${match.url}/life`} component={Life} />
</div>
)
就个人而言,我还发现这种方法更适合我使用带有代码拆分的动态导入,因为我可以在我的任何组件中添加动态路由。例如,
import Loadable from 'react-loadable';
const Loading = () => (
<div />
);
const Job = Loadable({
loader: () => import('./Job'),
loading: Loading,
});
const Life = Loadable({
loader: () => import('./Life'),
loading: Loading,
});
...
render() {
return (
...
<Route path={`${match.url}/job`} component={Job} />
<Route path={`${match.url}/life`} component={Life} />
)
}
动态路由的另一个很好的用例是创建响应式路由,这在react router docs和推荐阅读中有很好的解释。这是文档中的示例:
const App = () => (
<AppLayout>
<Route path="/invoices" component={Invoices}/>
</AppLayout>
)
const Invoices = () => (
<Layout>
{/* always show the nav */}
<InvoicesNav/>
<Media query={PRETTY_SMALL}>
{screenIsSmall => screenIsSmall
// small screen has no redirect
? <Switch>
<Route exact path="/invoices/dashboard" component={Dashboard}/>
<Route path="/invoices/:id" component={Invoice}/>
</Switch>
// large screen does!
: <Switch>
<Route exact path="/invoices/dashboard" component={Dashboard}/>
<Route path="/invoices/:id" component={Invoice}/>
<Redirect from="/invoices" to="/invoices/dashboard"/>
</Switch>
}
</Media>
</Layout>
)
总结一下文档Redirect,您会注意到使用动态路由将其添加到大屏幕尺寸变得多么简单和声明性。在这种情况下使用静态路由会非常麻烦,并且需要我们将所有路由放在一个地方。拥有动态路由简化了这个问题,因为现在逻辑变得可组合(如组件)。
有一些问题是动态路由不容易解决的。静态路由的一个优点是它允许在渲染之前检查和匹配路由。因此它被证明是有用的,尤其是在服务器端。react 路由器团队也在研究一个名为react-router-config的解决方案,引用其中:
随着 React Router v4 的引入,不再有集中的路由配置。在一些用例中,了解应用程序的所有潜在路线很有价值,例如:
- 在渲染下一个屏幕之前在服务器上或生命周期中加载数据
- 按名称链接到路线
- 静态分析
希望这可以很好地总结动态路由和静态路由以及它们的用例:)
根据 React-Router 文档:
当我们说动态路由时,我们指的是在您的应用程序呈现时发生的路由,而不是在正在运行的应用程序之外的配置或约定中。这意味着几乎所有东西都是 React Router 中的一个组件。
很清楚的解释是,所有路由都没有在应用程序开始时初始化,
在React-router v3或更低版本中,它使用静态路由,并且所有路由都将在顶层初始化,并且嵌套曾经像这样实现
<Router>
<Route path='/' component={App}>
<IndexRoute component={Dashboard} />
<Route path='users' component={Users}>
<IndexRoute component={Home}/>
<Route path="users/:id" component={User}/>
</Route>
</Route>
</Router>
通过这个 API 设置,react-router 重新实现了 React 的部分(生命周期等),它只是不符合 React 推荐使用的组合逻辑。
使用动态路由可以预见以下优点
嵌套路由
具有动态路由的嵌套路由更像
const App = () => (
<BrowserRouter>
{/* here's a div */}
<div>
{/* here's a Route */}
<Route path="/todos" component={Todos}/>
</div>
</BrowserRouter>
)
// when the url matches `/todos` this component renders
const Todos = ({ match }) => (
// here's a nested div
<div>
{/* here's a nested Route,
match.url helps us make a relative path */}
<Route
path={`${match.path}/:id`}
component={Todo}
/>
</div>
)
在上面的例子中,只有当 /todos 匹配到 route-path 时,才会挂载 Todo 组件,然后才/todos/:id定义 Route 路径。
响应路线
React-router 文档对此有一个很好的用例。
考虑用户导航到/invoices. 您的应用程序适应不同的屏幕尺寸,它们的视口很窄,因此您只向它们显示发票列表和发票链接dashboard。他们可以从那里更深入地导航。
但是在大屏幕上,导航位于左侧,仪表板或特定发票显示在右侧。
因此/invoices对于大屏幕来说不是有效的路线,我们希望重定向到/invoices/dashboard. 这可能会发生,用户将他/她的手机从portait to a landscape mode. 这可以使用动态路由轻松完成
const Invoices = () => (
<Layout>
{/* always show the nav */}
<InvoicesNav/>
<Media query={PRETTY_SMALL}>
{screenIsSmall => screenIsSmall
// small screen has no redirect
? <Switch>
<Route exact path="/invoices/dashboard" component={Dashboard}/>
<Route path="/invoices/:id" component={Invoice}/>
</Switch>
// large screen does!
: <Switch>
<Route exact path="/invoices/dashboard" component={Dashboard}/>
<Route path="/invoices/:id" component={Invoice}/>
<Redirect from="/invoices" to="/invoices/dashboard"/>
</Switch>
}
</Media>
</Layout>
)
将动态路由与 React Router 一起使用,考虑一下components,而不是静态路由。
代码拆分
网络的一大特色是我们不必让访问者在使用之前下载整个应用程序。您可以将代码拆分视为增量下载应用程序。This is made possible with Dynamic Routing.
它带来的优点是不需要一次下载所有代码,因此它使初始渲染速度更快。
这是一篇很好的文章,可以帮助您为您的应用程序设置 codeSplitting
编写可组合的认证路由
借助动态路由,它还可以更轻松地编写 PrivateRoutes(一种进行身份验证的 HOC),它允许对用户进行身份验证并为他们提供对特定路由的访问权限并以其他方式重定向。我所做的这个电话非常笼统
典型的私人路线看起来像
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route
{...rest}
render={props =>
fakeAuth.isAuthenticated ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: "/login",
state: { from: props.location }
}}
/>
)
}
/>
);
并且可以用作
<PrivateRoute path="/protected" component={Protected} />