React-Router v5文檔翻譯之設(shè)計(jì)思想

本項(xiàng)目Github地址,歡迎star

目錄

這篇指南是是用來解釋React Router使用時(shí)的心智模型。我們將其稱為“動態(tài)路由”,這與你可能更熟悉的“靜態(tài)路由”完全不同。

靜態(tài)路由

如果你使用過Rails,Express,Ember,Angular等框架,那么你已經(jīng)使用過了靜態(tài)路由。 在這些框架中,當(dāng)你在進(jìn)行任何渲染之前,會將路由聲明為應(yīng)用初始化的一部分。React Router pre-v4在大多數(shù)情況下也是靜態(tài)的。下面我們來看看如何在express中配置路由:

// Express Style routing:
app.get("/", handleIndex);
app.get("/invoices", handleInvoices);
app.get("/invoices/:id", handleInvoice);
app.get("/invoices/:id/edit", handleInvoiceEdit);

app.listen();

請注意在應(yīng)用監(jiān)聽請求之前是如何聲明路由的。我們使用的客戶端路由與其是相似當(dāng)。在Angular中,你可以預(yù)先聲明路由,然后在渲染之前將它們導(dǎo)入頂級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有一個(gè)常規(guī)的routes.js文件,在構(gòu)建時(shí)會讀取這個(gè)文件當(dāng)內(nèi)容并導(dǎo)入到應(yīng)用中。這會在應(yīng)用渲染前進(jìn)行。

// 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不同,但她們都遵循“靜態(tài)路由”模型。React Router遵循這個(gè)模型直到v4。但是要成功使用React Router,你需要忘記這一切。

背景

坦率地說,我們React Router直到v2版本所采取的開發(fā)方向感到非常沮喪。 我們(Michael和Ryan)感覺現(xiàn)在采用的這種路由方式受限于API,我們正在重新實(shí)現(xiàn)React(生命周期等)的部分,并且它與React給我們創(chuàng)造UI的心智模型不匹配。當(dāng)我們在研討會之前在一家酒店的走廊互相討論時(shí)。我們互相問道:“如果我們使用我們在之前討論的模式構(gòu)建路由會是什么樣子?”開發(fā)只需要幾個(gè)小時(shí),我們就有了一個(gè)驗(yàn)證的概念,我們知道她是未來我們想要路由。 我們最終意識到API并不應(yīng)該在React的“外部”,這是一個(gè)由React的其余部分組成并自然落實(shí)到位的API。我們認(rèn)為你會喜歡她。

動態(tài)路由

動態(tài)路由指的是在應(yīng)用渲染時(shí)發(fā)生的路由,而不是在正在運(yùn)行的應(yīng)用之外配置或規(guī)定好的路由。這意味著幾乎所有東西都是React Router中的一個(gè)組件。接下來看一下這個(gè)API是如何工作的:

首先,創(chuàng)建一個(gè)路由組件,將其渲染在應(yīng)用的頂部。

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

接下來,創(chuàng)建一個(gè)鏈接組件將其鏈接到一個(gè)新的地址。

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

最后,當(dāng)用戶查看‘/dashboard'路徑時(shí),渲染該路由并展示對應(yīng)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將不渲染任何東西。這就是它的全部內(nèi)容。

嵌套路由

很多路由庫都有一些“嵌套路由”的概念。如果你使用過React Router V4以前的版本,那么你就會知道我們也是這樣做的。然而當(dāng)你從靜態(tài)路由配置移動到動態(tài)渲染路由時(shí),該如何“嵌套路由”呢?

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僅僅是一個(gè)組件,就想一個(gè)普通的div一樣。

響應(yīng)路由

設(shè)想一下用戶導(dǎo)航到'/invoice'。你的應(yīng)用需要適用于不同的尺寸的屏幕,當(dāng)她們具有較窄的視口時(shí),你只需向其顯示發(fā)票列表和到發(fā)票詳情的鏈接。她們可以導(dǎo)航到更深入的層級。

Small Screen
url: /invoices

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

在更大的屏幕上,我們會想要顯示一個(gè)類別-詳細(xì)內(nèi)容的視圖,其中導(dǎo)航位于左側(cè),詳情或特定發(fā)票顯示在右側(cè)。

Large Screen
url: /invoices/dashboard

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

現(xiàn)在暫??紤]一下兩種屏幕尺寸的/invoice URL,她是大尺寸屏幕的有效路由嗎?我們應(yīng)該把右邊的東西放在什么位置?

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

在大屏幕上,'/invoice'不是有效的路線,但在小屏幕上她是有效的,更有趣的是,請考慮一個(gè)擁尺寸手機(jī)的人。她/他可以用橫屏和豎屏兩種方式來查看手機(jī)頁面。突然間,我們有足夠的空間來顯示類別-詳情這種UI,所以你應(yīng)該立即重定向!

React Router在先前版本的靜態(tài)路由并沒有真正成功的答案。但是,當(dāng)路由是動態(tài)的時(shí),你可以聲明性地重組這些功能。如果你開始考慮將路由作為UI而不是靜態(tài)配置,那么你會寫出以下代碼:

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

當(dāng)用戶將手機(jī)從縱向旋轉(zhuǎn)到橫向時(shí),此代碼會自動將其重定向到詳情頁。該組有效路由將根據(jù)用戶手中的移動設(shè)備的動態(tài)特性而改變。

這只是一個(gè)例子。我們還有許多其他問題可以討論,我們總結(jié)一下規(guī)律:我們應(yīng)該考慮組件,而不是靜態(tài)路由??紤]如何使用React的聲明可組合性來解決問題,因?yàn)閹缀趺總€(gè)“React Router問題”都可能是“React問題”。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。