|
| 1 | +## Route Configuration |
| 2 | + |
| 3 | +Let's start with the simple app from [the introduction](Introduction.md). |
| 4 | + |
| 5 | +```js |
| 6 | +import React from 'react'; |
| 7 | +import { Router, Route } from 'react-router'; |
| 8 | + |
| 9 | +var App = React.createClass({ |
| 10 | + render() { |
| 11 | + return ( |
| 12 | + <div> |
| 13 | + <h1>App</h1> |
| 14 | + <ul> |
| 15 | + <li><Link to="/about">About</Link></li> |
| 16 | + <li><Link to="/inbox">Inbox</Link></li> |
| 17 | + </ul> |
| 18 | + {this.props.children} |
| 19 | + </div> |
| 20 | + ) |
| 21 | + } |
| 22 | +}); |
| 23 | + |
| 24 | +var About = React.createClass({ |
| 25 | + render() { |
| 26 | + return <h3>About</h3>; |
| 27 | + } |
| 28 | +}); |
| 29 | + |
| 30 | +var Inbox = React.createClass({ |
| 31 | + render() { |
| 32 | + return ( |
| 33 | + <div> |
| 34 | + <h2>Inbox</h2> |
| 35 | + {this.props.children || "Welcome to your Inbox"} |
| 36 | + </div> |
| 37 | + ); |
| 38 | + } |
| 39 | +}); |
| 40 | + |
| 41 | +var Message = React.createClass({ |
| 42 | + render() { |
| 43 | + return <h3>Message {this.props.params.id}</h3>; |
| 44 | + } |
| 45 | +}); |
| 46 | + |
| 47 | +React.render(( |
| 48 | + <Router> |
| 49 | + <Route path="/" component={App}> |
| 50 | + <Route path="about" component={About} /> |
| 51 | + <Route path="inbox" component={Inbox}> |
| 52 | + <Route path="messages/:id" component={Message} /> |
| 53 | + </Route> |
| 54 | + </Route> |
| 55 | + </Router> |
| 56 | +), document.body); |
| 57 | +``` |
| 58 | + |
| 59 | +As configured, this app knows how to render the following 4 URLs: |
| 60 | + |
| 61 | +URL | Components |
| 62 | +------------------------|----------- |
| 63 | +`/` | `App` |
| 64 | +`/about` | `App -> About` |
| 65 | +`/inbox` | `App -> Inbox` |
| 66 | +`/inbox/messages/:id` | `App -> Inbox -> Message` |
| 67 | + |
| 68 | +### Adding an Index |
| 69 | + |
| 70 | +Imagine we'd like to render another component inside of `App` when the URL is `/`. Currently, `this.props.children` is `undefined` in this case. We can use an `<IndexRoute>` for that. |
| 71 | + |
| 72 | +```js |
| 73 | +import { IndexRoute } from 'react-router'; |
| 74 | + |
| 75 | +var Dashboard = React.createClass({ |
| 76 | + render() { |
| 77 | + return <div>Welcome to the app!</div>; |
| 78 | + } |
| 79 | +}); |
| 80 | + |
| 81 | +React.render(( |
| 82 | + <Router> |
| 83 | + <Route path="/" component={App}> |
| 84 | + {/* Show the dashboard at / */} |
| 85 | + <IndexRoute component={Dashboard} /> |
| 86 | + <Route path="about" component={About} /> |
| 87 | + <Route path="inbox" component={Inbox}> |
| 88 | + <Route path="messages/:id" component={Message} /> |
| 89 | + </Route> |
| 90 | + </Route> |
| 91 | + </Router> |
| 92 | +), document.body); |
| 93 | +``` |
| 94 | + |
| 95 | +Now, `this.props.children` will be a `<Dashboard>` element inside `App`'s `render` method! This functionality is similar to Apache's [`DirectoryIndex`](http://httpd.apache.org/docs/2.4/mod/mod_dir.html#directoryindex) or nginx's [`index`](http://nginx.org/en/docs/http/ngx_http_index_module.html#index) directive. |
| 96 | + |
| 97 | +Our sitemap now looks like this: |
| 98 | + |
| 99 | +URL | Components |
| 100 | +------------------------|----------- |
| 101 | +`/` | `App -> Dashboard` |
| 102 | +`/about` | `App -> About` |
| 103 | +`/inbox` | `App -> Inbox` |
| 104 | +`/inbox/messages/:id` | `App -> Inbox -> Message` |
| 105 | + |
| 106 | +### Decoupling the UI from the URL |
| 107 | + |
| 108 | +It would be nice if we could remove the `/inbox` segment from the `/inbox/messages/:id` URL, but still render `Message` nested inside the `App -> Inbox` UI. We can use an absolute path for that. |
| 109 | + |
| 110 | +```js |
| 111 | +React.render(( |
| 112 | + <Router> |
| 113 | + <Route path="/" component={App}> |
| 114 | + <IndexRoute component={Dashboard} /> |
| 115 | + <Route path="about" component={About} /> |
| 116 | + <Route path="inbox" component={Inbox}> |
| 117 | + {/* Use /messages/:id instead of messages/:id */} |
| 118 | + <Route path="/messages/:id" component={Message} /> |
| 119 | + </Route> |
| 120 | + </Route> |
| 121 | + </Router> |
| 122 | +), document.body); |
| 123 | +``` |
| 124 | + |
| 125 | +We can now render the following URLs: |
| 126 | + |
| 127 | +URL | Components |
| 128 | +------------------------|----------- |
| 129 | +`/` | `App -> Dashboard` |
| 130 | +`/about` | `App -> About` |
| 131 | +`/inbox` | `App -> Inbox` |
| 132 | +`/messages/:id` | `App -> Inbox -> Message` |
| 133 | + |
| 134 | +The ability to use absolute paths in deeply nested routes gives us complete control over what the URL looks like! We don't have to add more segments to the URL just to get nested UI. |
| 135 | + |
| 136 | +### Preserving URLs |
| 137 | + |
| 138 | +But wait just a minute ... we just changed a URL! [That's not cool](http://www.w3.org/Provider/Style/URI.html). Now everyone who had a link to `/inbox/messages/5` has a **broken link**. :( |
| 139 | + |
| 140 | +Not to worry. Redirects to the rescue! |
| 141 | + |
| 142 | +```js |
| 143 | +import { Redirect } from 'react-router'; |
| 144 | + |
| 145 | +React.render(( |
| 146 | + <Router> |
| 147 | + <Route path="/" component={App}> |
| 148 | + <IndexRoute component={Dashboard} /> |
| 149 | + <Route path="about" component={About} /> |
| 150 | + <Route path="inbox" component={Inbox}> |
| 151 | + <Route path="/messages/:id" component={Message} /> |
| 152 | + |
| 153 | + {/* Redirect /inbox/messages/:id to /messages/:id */} |
| 154 | + <Redirect from="messages/:id" to="/messages/:id" /> |
| 155 | + </Route> |
| 156 | + </Route> |
| 157 | + </Router> |
| 158 | +), document.body); |
| 159 | +``` |
| 160 | + |
| 161 | +Now when someone clicks on that link to `/inbox/messages/5` they'll automatically be redirected to `/messages/5`. We don't hate our users anymore! :highfive: |
0 commit comments