React Router 4

博主翻译原教程目的(加了一些博主自己解读),一是博主自己进一步了解React Router 4,二是官网的教程确实还需加强引导性和增加案例多样性。从React Router 4 的心智模型。看后面对这个词的解释,就明白了有些伙伴们对4的质疑。

目的

此指南的目的为了说明使用 React Router 4 时的心智模型。我们称之为的”动态路由“,这与你熟悉的”静态路由“有很大的不同。

注释:心智模型是经由经验及学习,脑海中对某些事物发展的过程,所写下的剧本,是个体为了要了解和解释他们的经验,所建构的知识结构,该模型受限于个体关于他们经验的内隐理论,这可能有很多或很少的正确性。

静态路由

如果你使用 Rails, Express, Ember, Angular 等。你已经使用了静态路由。在这些框架中,在任何渲染发生之前,将申明路由作为应用程序初始化一部分。
React Router 4 之前的版本也是静态的(主要是)。让我们看看在 Express 里如何配置路由:

const express = require('express');
const app = express();

app.get('/', handleIndex)
app.get('/invoices', handleInvoices)
app.get('/invoices/:id', handleInvoice)
app.get('/invoices/:id/edit', handleInvoiceEdit)

app.listen()

注意:在应用程序监听之前如何让路由被申明。这和我们使用的客户端路由是相似的。在 Angular 中,首先申明路由并且在渲染之间把他们导入到顶级的 AppMoudule :

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 文件,它可以构建读取并导入到应用程序里。同样,在应用渲染之前发生。

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 4之前也是这样的模式。

如果要使用React Router,那么你需要忘记这一切!

背景故事

坦白的说,我们非常郁闷,因为第二版采用了 React Router。我们感到被API 限制了。认识到我们正在重新实现 React 的一部份(生命周期等),并且它不能符合 React 给我们编写的用户界面的心智模型。

一次研究讨论会前,我们正走走过一家酒店的长走廊。我们相互讨论:”如果我们使用在研讨论会中的模式构建路由器会是什么样?“

动态路由

静态路由:任何渲染发生之前,将申明路由作为应用程序初始化一部分。

当我们说动态路由,在应用程序正在渲染时发生的路由,不是运行应用程序之外的配置或约定中。在React Router 中一切都是一个组件。下面是一个 API 回顾,看下它如何工作的。

首先,在应用顶部

// react-native
import { NativeRouter } from 'react-router-native'

// react-dom
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 时,会去渲染一个路由去显示用户界面。

const App = () => (
  <div>
    <nav>
      <Link to="/dashboard">Dashboard</Link>
    </nav>
    <div>
      <Route path="/dashboard" component={Dashboard}/>
    </div>
  </div>
)

路由将渲染 <Dashboard {...props}/>,props 是一些路由器特定的东西,看起来像 {match, location, history} 。如果 /dashboard 链接不存在,那么路由将呈现为空。这几乎就是全部了。

嵌套路由

什么情况下用到嵌套路由,比如应用左侧边栏是个菜单,点击不同内容时,右侧界面对应相应一个路由并且随着变化。

许多路由有一些概念性的 ”嵌套路由"。如果你已经使用过 React Router 4 之前的版本,那么也将知道它是什么。当你从一个静态路由配置移到动态的渲染路由,知道怎么做吗?怎么嵌套一个div?

const App = () => (
  <BrowserRouter>
    {/* 这里有个div */}
    <div>
        {/* 路由 */}
        <Route path="/tacos" component={Tacos}/>
    </div>
  </BrowserRouter>
)

// when the url matches `/tacos` this component renders
const Tacos  = ({ match }) => (
  // 有一个嵌套div
  <div>
    {/* 有一个嵌套路由,match.url 帮助我们做一个相对路径 */}
    <Route 
        path={match.url + '/carnitas'} 
        component={Carnitas} />
  </div>
)

可以看出,这里并没有嵌套 API ,路由只是一个组件而已,就像 div 一样。所以嵌套一个路由或 div , 照着这样做就行了。

响应式路由

用户先导航到 /invoices。应用能自适应不同尺寸的屏幕,它们有一个小的适配器,而且能展示它们 invoices 列表和链接到 invoice/dashboard。它们可以深度导航。

小屏幕
路由地址: /invoices

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

在一个大屏幕上,我们想点击左边的 Dashboard 就在右边显示一个对应导航的页面。

大屏幕
路由地址: /invoices/dashboard

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

我们思考一下,/invoices 路由地址是适用于两种屏幕的,在大屏幕上,它是有效路由吗?它右边呈现什么内容了?

大屏幕
路由地址: /invoices

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

在大屏幕上,/invoices 不是有效路由,但是在小屏幕上是有效路由。为了让事件更有趣,考虑一些伙伴会用大屏手机。他们先纵向方向浏览 /invoices ,然后把手机转向横向。突然,页面上有多余的空间来显示主界面,所以这里我们需要重定向。

React Router 以前版本的静态路由为这种情况是不能有可组合的方案。当路由是动态的,无论如何,你能声明式的编写这个功能。如果你开始想UI想路由,不是像静态配置那样,你的直觉会引导你到下面的代码:

const App = () => (
  <AppLayout>
    <Route path="/invoices" component={Invoices}/>
  </AppLayout>
)

const Invoices = () => (
  <Layout>

    {/* 一直显示的导航 */}
    <InvoicesNav/>

    <Media query={PRETTY_SMALL}>
      {screenIsSmall => screenIsSmall
        // 小屏幕时没有重定向
        ? <Switch>
            <Route exact path="/invoices/dashboard" component={Dashboard}/>
            <Route path="/invoices/:id" component={Invoice}/>
          </Switch>
        // 大屏幕时重定向!
        : <Switch>
            <Route exact path="/invoices/dashboard" component={Dashboard}/>
            <Route path="/invoices/:id" component={Invoice}/>
            // 重定向
            <Redirect from="/invoices" to="/invoices/dashboard"/>
          </Switch>
      }
    </Media>
  </Layout>
)

隋着用户的手机从纵向旋转到横向,这段代码将自动重定向它们到 dashboard ,这一组有效路由改变取决于移动设备在用户手中的动态状态。

这仅是一个案例。还有很多其他可以讨论的,我们总结的建议:为了让你理解React Router ,想想它是组件,不是一个静态路由,思考如何用 React 声明性可组合性解决问题,因为几乎每个"React Router 问题"大概是个”React 问题“。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容