我爱编程react

React Router 中文文档 1. React Route

2018-06-10  本文已影响184人  钟志弘

philosophy_React Router 4.0 的哲学

这篇文档主要解释了核心组件什么时候应该使用 REACT ROUTER,我们称这种解释为动态路由(Dynamic Routing), 它跟我们所熟悉的静态路由有非常大的不同。

1.1 什么是静态路由

如果你使用过 Rails, Express, Angular 之类的框架, 你肯定使用过静态路由。在与之类似的框架中,我们需要在应用程序渲染开始之前,也就是在程序的初始化过程中声明路由。 REACT ROUTER PRE-V4 (初期版本)很大程度上也属于静态路由。首先让我们来看一下在express中是如何配置路由的:

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

app.listen()

我们留意到,在app.listen方法之前,我们必须要声明路由。跟我们之前用过的客户端路由相似. 在 Angular 中,应用开始渲染之前,你需要最将路由声明在最前面并且将他们应用到最顶层的 AppModule中:

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 ,它的Build可以帮你读取并导入到应用程序里。同上,在你的app渲染之前的必须步骤(不知道原作者想表达什么,记住这有一个常规文件就好了):

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,你需要忘记以上所讲的东西。

1.2 背景故事

坦白讲,我们对我们发布的REACT ROUTER 2.x的发展方向非常的气馁. 我们(Micheal和Ryan)觉得被我们这些API所束缚,并且意识导我们正在重构的部分代码(lifecycles(生命周期)...),跟React给我们构建UI的核心组件并不对接。

当我们离开酒店大堂准备去一个研讨会,讨论应该怎么应对这个问题的时候,我们随口聊天:“如果我们使用在研讨会上宣传的模板来构建我们的路由,会怎么样呢?”

仅仅开发了一个小时,我们便有了react router4.0的我们想要的路由的核心概念,我们终结了不在react 外面的 API , 取而代之的是我们创造出来的,对未来的react更加兼容的API。我们相信你肯定会喜欢的。

1.3 动态路由(Dynamic Routing)

什么是动态路由? 我们觉得动态路由可以在你的app正在渲染的时候启动,而不是在一个配置或者或者一个正在运行的app外部的常规文件中。 也就是说几乎所有事情都可以通过react router中的一个组件来完成。 现在让我们用60s时间浏览一下API ,来看看它们是如何工作的:

首先,在你的目标文件中引入router,并且在app的头部渲染它:

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

最后,将你想要渲染的UI渲染到Route组件中。如此,当用户访问/dashboard的时候,你的页面就能正常工作了。

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

如果你想要传入一些特定的属性,例如:{match, localtion, history},那么Route会渲染一个<Dashboard {...props} /> 其中,props 包含了这些属性。如果用户并没有访问 /dashboard,那么 Route会返回null. 以上就是关于动态路由的很多事情。

1.4 嵌套路由(Nested Routes)

很多路由都有一些例如“嵌套路由”的概念。如果你已经使用之前发布的react router v4,那么你肯定已经知道这个玩意儿了!当你从静态路由配置过度到动态、呈现式路由,你该如何嵌套路由呢? 这跟你嵌套一个div一样简单?

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

为什么router 组件没有使用嵌套API( •̀ ω •́ )✧? 因为Route 只是一个组件,就跟DIV一样,所以从现在开始构建route简直跟构建div一样简单!

让我们来谈些棘手的吧。

1.5 响应式路由

考虑一个对用户呈现 /invoices。 你的app需要适应不同尺寸的屏幕, 他们有一个狭小的视图,并且你只能给他们一个发票(invoices)的列表和一个链接到invoice dashboard的链接,从而以进一步导航:

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      |                           |
|                      |                           |
+----------------------+---------------------------+

现在暂停一分钟然后想一想如何将 /invoices url适应两个大小的屏幕。这个路由甚至对大屏幕的路由有效?我们应该在视图中的右边放什么东西?

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

在大视图中,/invoices 并不是一个有效的路由(/invoices/dashboard才是),但是在小屏幕中它确是!想让这件事变得更有趣点?加入有人有一个巨大的手机,他们可以在纵向看到 /invoices ,并且如果他们旋转他们的手机到横向。这时我们有足够的空间去显示主-从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>
)

当用户把他们的手机从横向旋转为纵向的时候, 这段代码会自动重定位到 /invoices/dashboard url中。 路由的改变随着用户手中的设备旋转而改变。

这仅仅只是单单的案例。还有更多的案例我们可以讨论,但是为了节省时间,我们将这些案例总结为一个忠告:将你的直觉与react router的 保持一致,以组件的形式去实现路由,而不是静态配置形式。思考使用React的声明式组件的思想去解决问题,因为几乎所有react router的问题,都是 react 的问题。

上一篇下一篇

猜你喜欢

热点阅读