让前端飞Web前端之路前端开发

React-Router v5文档翻译之设计思想

2019-06-12  本文已影响0人  Harlan_Zhang

本项目Github地址,欢迎star

目录

这篇指南是是用来解释React Router使用时的心智模型。我们将其称为“动态路由”,这与你可能更熟悉的“静态路由”完全不同。

静态路由

如果你使用过Rails,Express,Ember,Angular等框架,那么你已经使用过了静态路由。 在这些框架中,当你在进行任何渲染之前,会将路由声明为应用初始化的一部分。React Router pre-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();

请注意在应用监听请求之前是如何声明路由的。我们使用的客户端路由与其是相似当。在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文件,在构建时会读取这个文件当内容并导入到应用中。这会在应用渲染前进行。

// 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不同,但她们都遵循“静态路由”模型。React Router遵循这个模型直到v4。但是要成功使用React Router,你需要忘记这一切。

背景

坦率地说,我们React Router直到v2版本所采取的开发方向感到非常沮丧。 我们(Michael和Ryan)感觉现在采用的这种路由方式受限于API,我们正在重新实现React(生命周期等)的部分,并且它与React给我们创造UI的心智模型不匹配。当我们在研讨会之前在一家酒店的走廊互相讨论时。我们互相问道:“如果我们使用我们在之前讨论的模式构建路由会是什么样子?”开发只需要几个小时,我们就有了一个验证的概念,我们知道她是未来我们想要路由。 我们最终意识到API并不应该在React的“外部”,这是一个由React的其余部分组成并自然落实到位的API。我们认为你会喜欢她。

动态路由

动态路由指的是在应用渲染时发生的路由,而不是在正在运行的应用之外配置或规定好的路由。这意味着几乎所有东西都是React Router中的一个组件。接下来看一下这个API是如何工作的:

首先,创建一个路由组件,将其渲染在应用的顶部。

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

接下来,创建一个链接组件将其链接到一个新的地址。

const App = () => (
  <div>
    <nav>
      <Link to="/dashboard">Dashboard</Link>
    </nav>
  </div>
);

最后,当用户查看‘/dashboard'路径时,渲染该路由并展示对应UI

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将不渲染任何东西。这就是它的全部内容。

嵌套路由

很多路由库都有一些“嵌套路由”的概念。如果你使用过React Router V4以前的版本,那么你就会知道我们也是这样做的。然而当你从静态路由配置移动到动态渲染路由时,该如何“嵌套路由”呢?

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

如上代码,React Router并没有嵌套的API,Router仅仅是一个组件,就想一个普通的div一样。

响应路由

设想一下用户导航到'/invoice'。你的应用需要适用于不同的尺寸的屏幕,当她们具有较窄的视口时,你只需向其显示发票列表和到发票详情的链接。她们可以导航到更深入的层级。

Small Screen
url: /invoices

+----------------------+
|                      |
|      Dashboard       |
|                      |
+----------------------+
|                      |
|      Invoice 01      |
|                      |
+----------------------+
|                      |
|      Invoice 02      |
|                      |
+----------------------+
|                      |
|      Invoice 03      |
|                      |
+----------------------+
|                      |
|      Invoice 04      |
|                      |
+----------------------+

在更大的屏幕上,我们会想要显示一个类别-详细内容的视图,其中导航位于左侧,详情或特定发票显示在右侧。

Large Screen
url: /invoices/dashboard

+----------------------+---------------------------+
|                      |                           |
|      Dashboard       |                           |
|                      |   Unpaid:             5   |
+----------------------+                           |
|                      |   Balance:   $53,543.00   |
|      Invoice 01      |                           |
|                      |   Past Due:           2   |
+----------------------+                           |
|                      |                           |
|      Invoice 02      |                           |
|                      |   +-------------------+   |
+----------------------+   |                   |   |
|                      |   |  +    +     +     |   |
|      Invoice 03      |   |  | +  |     |     |   |
|                      |   |  | |  |  +  |  +  |   |
+----------------------+   |  | |  |  |  |  |  |   |
|                      |   +--+-+--+--+--+--+--+   |
|      Invoice 04      |                           |
|                      |                           |
+----------------------+---------------------------+

现在暂停考虑一下两种屏幕尺寸的/invoice URL,她是大尺寸屏幕的有效路由吗?我们应该把右边的东西放在什么位置?

Large Screen
url: /invoices
+----------------------+---------------------------+
|                      |                           |
|      Dashboard       |                           |
|                      |                           |
+----------------------+                           |
|                      |                           |
|      Invoice 01      |                           |
|                      |                           |
+----------------------+                           |
|                      |                           |
|      Invoice 02      |             ???           |
|                      |                           |
+----------------------+                           |
|                      |                           |
|      Invoice 03      |                           |
|                      |                           |
+----------------------+                           |
|                      |                           |
|      Invoice 04      |                           |
|                      |                           |
+----------------------+---------------------------+

在大屏幕上,'/invoice'不是有效的路线,但在小屏幕上她是有效的,更有趣的是,请考虑一个拥尺寸手机的人。她/他可以用横屏和竖屏两种方式来查看手机页面。突然间,我们有足够的空间来显示类别-详情这种UI,所以你应该立即重定向!

React Router在先前版本的静态路由并没有真正成功的答案。但是,当路由是动态的时,你可以声明性地重组这些功能。如果你开始考虑将路由作为UI而不是静态配置,那么你会写出以下代码:

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

当用户将手机从纵向旋转到横向时,此代码会自动将其重定向到详情页。该组有效路由将根据用户手中的移动设备的动态特性而改变。

这只是一个例子。我们还有许多其他问题可以讨论,我们总结一下规律:我们应该考虑组件,而不是静态路由。考虑如何使用React的声明可组合性来解决问题,因为几乎每个“React Router问题”都可能是“React问题”。

上一篇下一篇

猜你喜欢

热点阅读