本指南的目的是解释使用React Router时的心智模型。我们将其称为“动态路由”,这与您可能更熟悉的“静态路由”完全不同。
静态路由
如果你使用过Rails, Express, Ember, Angular等框架,那么你已经使用过静态路由。
在这些框架中,在进行任何渲染之前,都将路由声明为应用初始化的一部分。
React Router v4版本之前也是静态的(大多数情况下)。
我们来看看如何在express
中配置路由:
// Express Style routing:
app.get("/", handleIndex);
app.get("/invoices", handleInvoices);
app.get("/invoices/:id", handleInvoice);
app.get("/invoices/:id/edit", handleInvoiceEdit);
app.listen();
注意在app侦听之前是如何进行路由的声明的。
我们使用客户端路由的方式都是相似的。
在Angular
中,您可以预先声明您的路由,然后在渲染之前将它们导入顶级AppModule:
// Angular Style routing:
const appRoutes: Routes = [
{
path: "crisis-center",
component: CrisisListComponent
},
{
path: "hero/:id",
component: HeroDetailComponent
},
{
path: "heroes",
component: HeroListComponent,
data: { title: "Heroes List" }
},
{
path: "",
redirectTo: "/heroes",
pathMatch: "full"
},
{
path: "**",
component: PageNotFoundComponent
}
];
@NgModule({
imports: [RouterModule.forRoot(appRoutes)]
})
export class AppModule {}
Ember
有一个传统的routes.js文件,构建会读取并导入到应用程序中。这同样发生在你的app渲染之前。
// Ember Style Router:
Router.map(function() {
this.route("about");
this.route("contact");
this.route("rentals", function() {
this.route("show", { path: "/:rental_id" });
});
});
export default Router;
尽管API不同,但它们都共享“静态路由”模型。 在v4版本之前,React路由器是由该模型引导出来的。要成功使用React Router,您需要忘记这一切!
背景(可不用看)
坦白说,我们对于v2版本的React Router感到非常沮丧。我们(Michael和Ryan)感觉受到API的限制,认识到虽然我们重新实现了React(生命周期等)的部分,但它与React给我们创建UI的心理模型不匹配。
在研讨会讨论如何应对之前,我们正走过酒店的走廊。我们互相问道:“如果我们使用我们在工作室教授的模式构建路由器会是什么样子?”
开发只需要几个小时,我们就有一个概念验证,我们知道这是我们想要的路由的未来。我们最终得到的API并不是React的“外部”,这是一个由React的其余部分组成或自然落实到位的API。我们认为你会喜欢它。
动态路由
当我们说动态路由时,我们指的是在您的应用渲染时发生的路由,而不是在正在运行的应用之外的配置或约定中。这意味着几乎所有东西都是React Router中的一个组件。这是对API的60秒评论,看看它是如何工作的:
首先,为自己定位的环境抓住自己的路由器组件,并将其呈现在应用的顶部。
// react-native
import { NativeRouter } from "react-router-native";
// react-dom (what we'll use here)
import { BrowserRouter } from "react-router-dom";
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
el
);
其次,使用<Link>组件导航到新地址。
const App = () => (
<div>
<nav>
<Link to="/dashboard">Dashboard</Link>
</nav>
</div>
);
最后,当用户访问地址/dashboard时,使用<Route>渲染出某些内容(这里是Dashboard组件)。
const App = () => (
<div>
<nav>
<Link to="/dashboard">Dashboard</Link>
</nav>
<div>
<Route path="/dashboard" component={Dashboard} />
</div>
</div>
);
<Route>将会渲染<Dashboard {...props}/>,这里的props是路由的特殊对象{match, location, history}。如果用户不在/dashboard这个路径,那么<Route>这里就会渲染null, 也就是什么都不显示。
这就是它的全部内容。
嵌套路由
很多路由器都有一些“嵌套路由”的概念。如果您在v4之前使用过React Router的版本,那么您也知道它也是如此!当您从静态路由配置移动到动态渲染路由时,如何“嵌套路由”?那么,你是如何嵌套一个‘div’的?
路由器没有“嵌套”API?<Route>只是一个组件,就像div一样。因此,为了嵌套路由或div,你只需像使用div一样使用<Route>。
const App = () => (
<BrowserRouter>
{/* here's a div */}
<div>
{/* here's a Route */}
<Route path="/tacos" component={Tacos} />
</div>
</BrowserRouter>
);
// when the url matches `/tacos` this component renders
const Tacos = ({ match }) => (
// here's a nested div
<div>
{/* here's a nested Route,
match.url helps us make a relative path */}
<Route path={match.url + "/carnitas"} component={Carnitas} />
</div>
);
响应路由
假如用户导航到/invoices时,您的应用要适应于不同的屏幕尺寸,它们都具有较窄的视口,那您只需向其显示发票列表和以及不同发票内容的链接。
在更大的屏幕上,我们想要显示一个主 - 详细视图,其中导航位于左侧,在右侧显示相应的导航的内容。
以下代码:
当用户将手机从纵向旋转到横向时,此代码会自动将其重定向到/invoices/dashboar。该组有效路由根据用户手中的移动设备的动态特性而改变。
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>
);