diff options
author | Aldo Cortesi <aldo@nullcube.com> | 2014-09-10 14:22:26 +1200 |
---|---|---|
committer | Aldo Cortesi <aldo@nullcube.com> | 2014-09-10 14:23:10 +1200 |
commit | 0510c9b111aed03d0d3680db63614d50f231745c (patch) | |
tree | 0d2fec5d46a3cb984a8b12e36db2f44a1a8eaa5a /web/src/vendor/react-router/docs/guides/overview.md | |
parent | 76982937a68a2adaf96ec2d258e369d7c871a609 (diff) | |
download | mitmproxy-0510c9b111aed03d0d3680db63614d50f231745c.tar.gz mitmproxy-0510c9b111aed03d0d3680db63614d50f231745c.tar.bz2 mitmproxy-0510c9b111aed03d0d3680db63614d50f231745c.zip |
Client-side framework for web application
Diffstat (limited to 'web/src/vendor/react-router/docs/guides/overview.md')
-rw-r--r-- | web/src/vendor/react-router/docs/guides/overview.md | 373 |
1 files changed, 373 insertions, 0 deletions
diff --git a/web/src/vendor/react-router/docs/guides/overview.md b/web/src/vendor/react-router/docs/guides/overview.md new file mode 100644 index 00000000..9acd8115 --- /dev/null +++ b/web/src/vendor/react-router/docs/guides/overview.md @@ -0,0 +1,373 @@ +React Router Guide +================== + +Nesting UI is at the core of React Router. Think about any user +interface you're accustomed to, there is likely some shared UI as you +navigate around the application. + +Let's imagine a little app with a dashboard, inbox, and calendar. + +``` ++---------------------------------------------------------+ +| +---------+ +-------+ +--------+ | +| |Dashboard| | Inbox | |Calendar| Logged in as Joe | +| +---------+ +-------+ +--------+ | ++---------------------------------------------------------+ +| | +| Dashboard | +| | +| | +| +---------------------+ +----------------------+ | +| | | | | | +| | + + | +---------> | | +| | | | | | | | +| | | + | | +-------------> | | +| | | | + | | | | | +| | | | | | | | | | +| +-+---+----+-----+----+ +----------------------+ | +| | ++---------------------------------------------------------+ +``` + +We have three main screens here with the top section of UI being +persistent. + +Without React Router +-------------------- + +Without this router, you'd share that UI by repeating render code across +your views, probably with a `<Header/>` component: + +```js +var Header = React.createClass({ + render: function() { + return ( + <header> + <ul> + <li><a href="/">Dashboard</a></li> + <li><a href="/inbox">Inbox</a></li> + <li><a href="/calendar">Calendar</a></li> + </ul> + Logged in as Joe + </header> + ); + } +}); + +var DashboardRoute = React.createClass({ + render: function() { + return ( + <div> + <Header/> + <Dashboard/> + </div> + ); + } +}); + +var InboxRoute = React.createClass({ + render: function() { + return ( + <div> + <Header/> + <Inbox/> + </div> + ); + } +}); + +var CalendarRoute = React.createClass({ + render: function() { + return ( + <div> + <Header/> + <Calendar/> + </div> + ); + } +}); + +// Not React Router API +otherRouter.route('/', function() { + React.renderComponent(<DashboardRoute/>, document.body); +}); + +otherRouter.route('/inbox', function() { + React.renderComponent(<InboxRoute/>, document.body); +}); + +otherRouter.route('/calendar', function() { + React.renderComponent(<CalendarRoute/>, document.body); +}); + +``` + +The three main view's render methods are nearly identical. While one +level of shared UI like this is pretty easy to handle, getting deeper +and deeper adds more complexity, along with lots of `switch` branching, +etc. + +React Router embraces this common pattern among user interfaces by +nesting the views for you. + +With React Router +----------------- + +Here's how it works: + +1. You declare your view hierarchy with nested `<Route/>`s and provide + them with a React component to handle the route when its active. + +2. React Router will match the deepest route against the URL, and then + activate the entire tree of routes on that branch, nesting all the + UI. + +3. You access the active route handler in the props of the parent route. + +```js +var App = React.createClass({ + render: function() { + return ( + <div> + <header> + <ul> + <li><Link to="app">Dashboard</Link></li> + <li><Link to="inbox">Inbox</Link></li> + <li><Link to="calendar">Calendar</Link></li> + </ul> + Logged in as Joe + </header> + + {/* this is the important part */} + <this.props.activeRouteHandler/> + </div> + ); + } +}); + +var routes = ( + <Routes location="history"> + <Route name="app" path="/" handler={App}> + <Route name="inbox" handler={Inbox}/> + <Route name="calendar" handler={Calendar}/> + <DefaultRoute handler={Dashboard}/> + </Route> + </Routes> +); + +React.renderComponent(routes, document.body); +``` + +When the user lands at `/inbox`, the route named `inbox` gets matched so +its parent route will render the `App` component, and since `inbox` is +active, you get `Inbox` as `this.props.activeRouteHandler`. This is +nearly identical to `{{outlet}}` from Ember or `<div ng-view/>` from +angular. + +When the user navigates to `/calendar`, the same thing happens except +now `Calendar` is the `activeRouteHandler` in `App`'s render method. + +Finally, when the user navigates to the path `/`, `App` is active, and +notices that it has a `DefaultRoute`, so it receives `Dashboard` as the +`activeRouteHandler`. If a `DefaultRoute` is defined, it will be active +when the parent's route is matched exactly. + +Note that we don't need the `<Header/>` component since we don't have to +repeat it anymore. React Router shares that UI for us from one place. + +More Nesting +------------ + +Nesting arbitarily deep UI is not a problem. Consider the `Inbox` +screen: it has a master list of messages on the left, a detail view of +the message on the right, and a toolbar over the top. The toolbar and +list are persistent, meanwhile the message view changes as the user +navigates through the messages. + +``` ++---------------------------------------------------------------------+ +| +---------+ +-------+ +--------+ | +| |Dashboard| | Inbox | |Calendar| Logged in as Joe | +| +---------+ +-------+ +--------+ | ++---------------------------------------------------------------------+ +| +---------+ +-------+ +--------------+ | +| | Compose | | Reply | |Inbox Settings| | +| +---------+ +-------+ +--------------+ | ++-------------------+-------------------------------------------------+ +| David Brown | | +| Hey, we need to...| | +| | | +| 12:30pm | | ++-------------------+ 32 Unread Messages | +| Mary Sweeney | | +| I followed up w...| 456 Total Messages | +| | | +| 12:10pm | 3 Draft Messages | ++-------------------+ | +| DeMarcus Jones | | +| check this out ...| | +| | | +| 11:25am | | ++-------------------+-------------------------------------------------+ +``` + +Let's see how React Router handles this: + +```js +var Inbox = React.createClass({ + render: function() { + return ( + <div> + <Toolbar/> + <Messages/> + <this.props.activeRouteHandler/> + </div> + ); + } +}); + +var routes = ( + <Routes location="history"> + <Route handler={App}> + + <Route name="inbox" handler={Inbox}> + <Route name="message" path=":messageId" handler={Message}/> + <DefaultRoute handler={InboxStats}/> + </Route> + + <Route name="calendar" handler={Calendar}/> + <DefaultRoute handler={Dashboard}/> + + </Route> + </Routes> +); +``` + +- Inbox now has `this.props.activeRouteHandler` in its render method, + exactly like its parent. +- We added a child routes to `inbox`; messages or the stats page can now + render into it. + +Nesting a new level of UI does not increase the complexity of your code. +You simply nest some routes and render them with `activeRouteHandler`. + +Dynamic Segments +---------------- + +When we added the `message` route, we introduced a "dynamic segment" to +the URL. These segements get parsed from the url and passed into your +route handler on `this.props.params`. + +Remember our message route looks like this: + +```xml +<Route name="message" path=":messageId" handler={Message}/> +``` + +Lets look at accessing the `messageId` in `Message`. + +```js +var Message = React.createClass({ + render: function() { + return ( + <div>{this.props.params.messageId}</div> + ); + } +}); +``` + +Assuming the user navigates to `/inbox/123`, `this.props.params.messageId` is +going to be `'123'`. Check out the [AsyncState][AsyncState] mixin to see +how you can turn this parameter into state on your component. Or for a +more basic approach, make an ajax call in `componentDidMount` with the +value. + +Important Note About Dynamic Segments +------------------------------------- + +If you have dynamic segments in your URL, a transition from `/users/123` +to `/users/456` does not call `getInitialState`, `componentWillMount` or +`componentWillUnmount`. If you are using those lifecycle hooks to fetch +data and set state, you will also need to implement +`componentWillReceiveProps` on your handler, just like any other +component whose props are changing. This way you can leverage the +performance of the React DOM diff algorithm. Look at the `Contact` +handler in the `master-detail` example. + +If you'd rather be lazy, you can use the `addHandlerKey` option and set +it to `true` on your route to opt-out of the performance. See also +[Route][Route]. + +Scrolling +--------- + +By default, the router will manage the scroll position between route +transitions. When a user clicks "back" or "forward", it will restore +their scroll position. If they visit a new route, it will automatically +scroll the window to the top. You can opt out of this with the +`preserverScrollPosition` option on [Routes][Routes] or [Route][Route]. + +Bells and Whistles +------------------ + +### `<Link/>` + +The `<Link/>` component allows you to conveniently navigate users around +the application with accessible anchor tags that don't break normal link +functionality like control/command clicking to open in a new tab. Also, +when the route a link references is active, you get the `active` css +class to easily style your UI. + +### `<NotFoundRoute/>` + +At any level of your UI nesting, you can render a handler if the url +beyond what was matched isn't recognized. + +```xml +<Routes location="history"> + <Route path="/" handler={App}> + <Route name="inbox" path="/inbox" handler={Inbox}> + <!-- + will render inside the `Inbox` UI for any paths not recognized + after the parent route's path `/inbox/*` + --> + <NotFoundRoute handler={InboxNotFound} + <Route name="message" path="/inbox/:messageId" handler={Message}/> + <DefaultRoute handler={InboxStats}/> + </Route> + <Route name="calendar" path="/calendar" handler={Calendar}/> + <DefaultRoute handler={Dashboard}/> + </Route> + <!-- will catch any route that isn't recognized at all --> + <NotFoundRoute handler={NotFound} +</Routes> +``` + +### `<Redirect/>` + +URLs in an app change, so we made it easy to not break the old ones. + +```xml +<Route name="message" path="/inbox/:messageId" handler={Message} /> +<Redirect path="/messages/:messageId" to="message" /> +``` + +Path Matching +------------- + +There's a lot more to be said about path matching, check out the [Path +Matching Guide][path-matching]. + +API Documentation +----------------- + +That's the gist of what this router is all about, but there's a lot more +it has to offer. Check out the [API Docs][API] to learn about +redirecting transitions, query parameters and more. + + [AsyncState]:../api/mixins/AsyncState.md + [Route]:../api/components/Route.md + [Routes]:../api/components/Routes.md + [API]:../api/ + [path-matching]:./path-matching.md + |