@@ -10,7 +10,7 @@ Let's imagine a little app with a dashboard, inbox, and calendar.
10
10
```
11
11
+---------------------------------------------------------+
12
12
| +---------+ +-------+ +--------+ |
13
- | |Dashboard| | Inbox | |Calendar| Logged in as Joe |
13
+ | |Dashboard| | Inbox | |Calendar| Logged in as Jane |
14
14
| +---------+ +-------+ +--------+ |
15
15
+---------------------------------------------------------+
16
16
| |
@@ -48,7 +48,7 @@ var Header = React.createClass({
48
48
< li>< a href= " /inbox" > Inbox< / a>< / li>
49
49
< li>< a href= " /calendar" > Calendar< / a>< / li>
50
50
< / ul>
51
- Logged in as Joe
51
+ Logged in as Jane
52
52
< / header>
53
53
);
54
54
}
@@ -99,30 +99,49 @@ otherRouter.route('/inbox', function () {
99
99
otherRouter .route (' /calendar' , function () {
100
100
React .renderComponent (< CalendarRoute/ > , document .body );
101
101
});
102
-
103
102
```
104
103
105
104
The three main view's render methods are nearly identical. While one
106
105
level of shared UI like this is pretty easy to handle, getting deeper
107
- and deeper adds more complexity, along with lots of ` switch ` branching,
108
- etc.
106
+ and deeper adds more complexity.
109
107
110
- React Router embraces this common pattern among user interfaces by
111
- nesting the views for you.
108
+ Other approaches might introduce a lot of ` if/else ` or ` switch/case `
109
+ into your app if you pass the route information down through the app
110
+ hierarchy via props.
111
+
112
+ ``` js
113
+ var App = React .createClass ({
114
+ render : function () {
115
+ var page;
116
+ switch (this .props .page ) {
117
+ case ' dashboard' : page = < Dashboard/ > ; break ;
118
+ case ' inbox' : page = < Dashboard/ > ; break ;
119
+ default : page = < Index / > ; break ;
120
+ }
121
+ return (
122
+ < div> {page}< / div>
123
+ );
124
+ }
125
+ });
126
+ ```
127
+
128
+ React Router embraces the common pattern of shared UI among user
129
+ interfaces by nesting the views for you, decreasing boilerplate.
112
130
113
131
With React Router
114
132
-----------------
115
133
116
134
Here's how it works:
117
135
118
136
1 . You declare your view hierarchy with nested ` <Route/> ` s and provide
119
- them with a React component to handle the route when its active.
137
+ them with a React element to handle the route when its active.
120
138
121
139
2 . React Router will match the deepest route against the URL, and then
122
140
activate the entire tree of routes on that branch, nesting all the
123
141
UI.
124
142
125
- 3 . You access the active route handler in the props of the parent route.
143
+ 3 . You simply call ` <RouteHandler/> ` and it will render the active child
144
+ route.
126
145
127
146
``` js
128
147
var App = React .createClass ({
@@ -135,41 +154,46 @@ var App = React.createClass({
135
154
< li>< Link to= " inbox" > Inbox< / Link>< / li>
136
155
< li>< Link to= " calendar" > Calendar< / Link>< / li>
137
156
< / ul>
138
- Logged in as Joe
157
+ Logged in as Jane
139
158
< / header>
140
159
141
160
{/* this is the important part */ }
142
- < this . props . activeRouteHandler / >
161
+ < RouteHandler / >
143
162
< / div>
144
163
);
145
164
}
146
165
});
147
166
148
167
var routes = (
149
- < Routes location= " history" >
150
- < Route name= " app" path= " /" handler= {App}>
151
- < Route name= " inbox" handler= {Inbox}/ >
152
- < Route name= " calendar" handler= {Calendar}/ >
153
- < DefaultRoute handler= {Dashboard}/ >
154
- < / Route>
155
- < / Routes>
168
+ < Route name= " app" path= " /" handler= {App}>
169
+ < Route name= " inbox" handler= {Inbox}/ >
170
+ < Route name= " calendar" handler= {Calendar}/ >
171
+ < DefaultRoute handler= {Dashboard}/ >
172
+ < / Route>
156
173
);
157
174
158
- React .renderComponent (routes, document .body );
175
+ Router .run (routes, function (Handler ) {
176
+ React .renderComponent (< Handler/ > , document .body );
177
+ });
178
+
159
179
```
160
180
161
181
When the user lands at ` /inbox ` , the route named ` inbox ` gets matched so
162
- its parent route will render the ` App ` component, and since ` inbox ` is
163
- active, you get ` Inbox ` as ` this.props.activeRouteHandler ` . This is
164
- nearly identical to ` {{outlet}} ` from Ember or ` <div ng-view/> ` from
165
- angular.
182
+ its parent route, ` app ` , is also matched. The ` run ` callback receives
183
+ ` Handler ` , that has all of this match information wrapped up in it.
184
+
185
+ Rendering ` Handler ` is really just rendering ` App ` since its the highest
186
+ matched route handler. Since ` inbox ` is the active child route,
187
+ rendering ` <RouteHandler/> ` in ` App ` renders the ` Inbox ` component.
188
+ ` <RouteHandler/> ` is nearly identical to ` {{outlet}} ` from Ember or
189
+ ` <div ng-view/> ` from angular.
166
190
167
191
When the user navigates to ` /calendar ` , the same thing happens except
168
- now ` Calendar ` is the ` activeRouteHandler ` in ` App ` 's render method.
192
+ now ` Calendar ` is the ` <RouteHandler/> ` in ` App ` 's render method.
169
193
170
194
Finally, when the user navigates to the path ` / ` , ` App ` is active, and
171
- notices that it has a ` DefaultRoute ` , so it receives ` Dashboard ` as the
172
- ` activeRouteHandler ` . If a ` DefaultRoute ` is defined, it will be active
195
+ notices that it has a ` DefaultRoute ` , so ` Dashboard ` becomes the new
196
+ ` <RouteHandler/> ` . If a ` DefaultRoute ` is defined, it will be active
173
197
when the parent's route is matched exactly.
174
198
175
199
Note that we don't need the ` <Header/> ` component since we don't have to
@@ -187,7 +211,7 @@ navigates through the messages.
187
211
```
188
212
+---------------------------------------------------------------------+
189
213
| +---------+ +-------+ +--------+ |
190
- | |Dashboard| | Inbox | |Calendar| Logged in as Joe |
214
+ | |Dashboard| | Inbox | |Calendar| Logged in as Jane |
191
215
| +---------+ +-------+ +--------+ |
192
216
+---------------------------------------------------------------------+
193
217
| +---------+ +-------+ +--------------+ |
@@ -220,43 +244,42 @@ var Inbox = React.createClass({
220
244
< div>
221
245
< Toolbar/ >
222
246
< Messages/ >
223
- < this . props . activeRouteHandler / >
247
+ < RouteHandler / >
224
248
< / div>
225
249
);
226
250
}
227
251
});
228
252
229
253
var routes = (
230
- < Routes location= " history" >
231
- < Route handler= {App}>
254
+ < Route handler= {App}>
232
255
233
- < Route name= " inbox" handler= {Inbox}>
234
- < Route name= " message" path= " :messageId" handler= {Message}/ >
235
- < DefaultRoute handler= {InboxStats}/ >
236
- < / Route>
256
+ < Route name= " inbox" handler= {Inbox}>
257
+ < Route name= " message" path= " :messageId" handler= {Message}/ >
258
+ < DefaultRoute handler= {InboxStats}/ >
259
+ < / Route>
237
260
238
- < Route name= " calendar" handler= {Calendar}/ >
239
- < DefaultRoute handler= {Dashboard}/ >
261
+ < Route name= " calendar" handler= {Calendar}/ >
262
+ < DefaultRoute handler= {Dashboard}/ >
240
263
241
- < / Route>
242
- < / Routes>
264
+ < / Route>
243
265
);
244
266
```
245
267
246
- - Inbox now has ` this.props.activeRouteHandler ` in its render method,
268
+ - Inbox now has a ` <RouteHandler/> ` in its render method,
247
269
exactly like its parent.
248
- - We added a child routes to ` inbox ` ; messages or the stats page can now
270
+ - We added child routes to ` inbox ` ; the messages or stats page can now
249
271
render into it.
250
272
251
273
Nesting a new level of UI does not increase the complexity of your code.
252
- You simply nest some routes and render them with ` activeRouteHandler ` .
274
+ You simply nest some routes and render them with ` <RouteHandler/> ` .
253
275
254
276
Dynamic Segments
255
277
----------------
256
278
257
279
When we added the ` message ` route, we introduced a "dynamic segment" to
258
- the URL. These segements get parsed from the url and passed into your
259
- route handler on ` this.props.params ` .
280
+ the URL. These segements get parsed from the url and are available in
281
+ the ` run ` callback, or from the ` State ` mixin. Let's see how we can
282
+ access the params.
260
283
261
284
Remember our message route looks like this:
262
285
@@ -268,17 +291,54 @@ Lets look at accessing the `messageId` in `Message`.
268
291
269
292
``` js
270
293
var Message = React .createClass ({
294
+ mixins: [Router .State ],
271
295
render : function () {
272
296
return (
273
- < div> {this .props . params .messageId }< / div>
297
+ < div> {this .getParams () .messageId }< / div>
274
298
);
275
299
}
276
300
});
277
301
```
278
302
279
- Assuming the user navigates to ` /inbox/123 ` , ` this.props.params .messageId ` is
303
+ Assuming the user navigates to ` /inbox/123 ` , ` this.getParams() .messageId ` is
280
304
going to be ` '123' ` .
281
305
306
+ Alternatively, you can pass the param data down through the view
307
+ hierarchy from the ` run ` callback and access the params with
308
+ ` this.props.params ` .
309
+
310
+ ``` js
311
+ Router .run (routes, function (Handler , state ) {
312
+ var params = state .params ;
313
+ React .renderComponent (< Handler params= {params}/ > , document .body );
314
+ });
315
+
316
+ // and then pass the params down to every use of `<RouteHandler/>`
317
+ < RouteHandler {... this .props }/ >
318
+
319
+ // Inbox ends up looking like this
320
+ var Inbox = React .createClass ({
321
+ render : function () {
322
+ return (
323
+ < div>
324
+ < Toolbar/ >
325
+ < Messages/ >
326
+ < RouteHandler {... this .props }/ >
327
+ < / div>
328
+ );
329
+ }
330
+ });
331
+
332
+ // and Message changes to:
333
+ var Message = React .createClass ({
334
+ render : function () {
335
+ return (
336
+ < div> {this .props .params .messageId }< / div>
337
+ );
338
+ }
339
+ });
340
+ ```
341
+
282
342
Important Note About Dynamic Segments
283
343
-------------------------------------
284
344
@@ -291,10 +351,6 @@ component whose props are changing. This way you can leverage the
291
351
performance of the React DOM diff algorithm. Look at the ` Contact `
292
352
handler in the ` master-detail ` example.
293
353
294
- If you'd rather be lazy, you can use the ` addHandlerKey ` option and set
295
- it to ` true ` on your route to opt-out of the performance. See also
296
- [ Route] [ Route ] .
297
-
298
354
Scrolling
299
355
---------
300
356
@@ -321,23 +377,21 @@ At any level of your UI nesting, you can render a handler if the url
321
377
beyond what was matched isn't recognized.
322
378
323
379
``` xml
324
- <Routes location =" history" >
325
- <Route path =" /" handler ={App}>
326
- <Route name =" inbox" path =" /inbox" handler ={Inbox}>
327
- <!--
328
- will render inside the `Inbox` UI for any paths not recognized
329
- after the parent route's path `/inbox/*`
330
- -->
331
- <NotFoundRoute handler ={InboxNotFound}/>
332
- <Route name =" message" path =" /inbox/:messageId" handler ={Message}/>
333
- <DefaultRoute handler ={InboxStats}/>
334
- </Route >
335
- <Route name =" calendar" path =" /calendar" handler ={Calendar}/>
336
- <DefaultRoute handler ={Dashboard}/>
380
+ <Route path =" /" handler ={App}>
381
+ <Route name =" inbox" path =" /inbox" handler ={Inbox}>
382
+ <!--
383
+ will render inside the `Inbox` UI for any paths not recognized
384
+ after the parent route's path `/inbox/*`
385
+ -->
386
+ <NotFoundRoute handler ={InboxNotFound}/>
387
+ <Route name =" message" path =" /inbox/:messageId" handler ={Message}/>
388
+ <DefaultRoute handler ={InboxStats}/>
337
389
</Route >
338
- <!-- will catch any route that isn't recognized at all -->
339
- <NotFoundRoute handler ={NotFound}/>
340
- </Routes >
390
+ <Route name =" calendar" path =" /calendar" handler ={Calendar}/>
391
+ <DefaultRoute handler ={Dashboard}/>
392
+ </Route >
393
+ <!-- will catch any route that isn't recognized at all -->
394
+ <NotFoundRoute handler ={NotFound}/>
341
395
```
342
396
343
397
### ` <Redirect/> `
@@ -346,7 +400,7 @@ URLs in an app change, so we made it easy to not break the old ones.
346
400
347
401
``` xml
348
402
<Route name =" message" path =" /inbox/:messageId" handler ={Message} />
349
- <Redirect path =" /messages/:messageId" to =" message" />
403
+ <Redirect from =" /messages/:messageId" to =" message" />
350
404
```
351
405
352
406
Path Matching
@@ -363,8 +417,8 @@ it has to offer. Check out the [API Docs][API] to learn about
363
417
redirecting transitions, query parameters and more.
364
418
365
419
[ AsyncState ] :../api/mixins/AsyncState.md
366
- [ Route ] :../api/elements /Route.md
367
- [ Routes ] :../api/elements /Routes.md
420
+ [ Route ] :../api/components /Route.md
421
+ [ Routes ] :../api/components /Routes.md
368
422
[ API ] :../api/
369
423
[ path-matching ] :./path-matching.md
370
424
@@ -376,7 +430,6 @@ In order for the above examples to work in a CommonJS environment you'll need to
376
430
```
377
431
var Router = require('react-router');
378
432
var Route = Router.Route;
379
- var Routes = Router.Routes;
380
433
var NotFoundRoute = Router.NotFoundRoute;
381
434
var DefaultRoute = Router.DefaultRoute;
382
435
var Link = Router.Link;
0 commit comments