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 的问题。
网友评论