React-Router v5文檔翻譯之設計思想

本項目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問題”。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,250評論 6 530
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 97,923評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,041評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,475評論 1 308
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,253評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,801評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,882評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,023評論 0 285
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,530評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,494評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,639評論 1 366
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,177評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,890評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,289評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,552評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,242評論 3 389
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,626評論 2 370