Upload
rob-gietema
View
1.363
Download
1
Embed Size (px)
Citation preview
React RouterReact Meetup XXL - September 23, 2015
- Rob Gietema @robgietema
Who am I?
What is react-router?
Routing url to React ComponentRoute /about to <About />Route /user/1234 to <User />Route /user/1234?message=Hi to <User />
Michael Jackson & Ryan Florence
2.002 commits53 releases
197 contributors180k downloads / month
What does it look like?
Defining routes
Simple exampleimport { Route } from 'react-router';
const routes = ( <Route handler={App} path="/"> <Route name="about" handler={About} /> </Route>);
About page is available at /about
Using custom pathimport { Route } from 'react-router';
const routes = ( <Route handler={App} path="/"> <Route name="about" path="my-about" handler={About} /> </Route>);
About page is available at /my-about
Default routeimport { Route, DefaultRoute } from 'react-router';
const routes = ( <Route handler={App} path="/"> <DefaultRoute handler={Home} /> <Route name="about" handler={About} /> </Route>);
Home is available at /
Not found routeimport { Route, NotFoundRoute } from 'react-router';
const routes = ( <Route handler={App} path="/"> <Route name="about" handler={About} /> <NotFoundRoute handler={NotFound}/> </Route>);
Nestingimport { Route } from 'react-router';
const routes = ( <Route handler={App} path="/"> <Route name="users" handler={Users}> <Route name="recent-users" path="recent" handler={RecentUsers} /> </Route> </Route>);
Recent users available at /users/recent
Paramsimport { Route } from 'react-router';
const routes = ( <Route handler={App} path="/"> <Route name="users" handler={Users}> <Route name="user" path="/user/:userId" handler={User} /> </Route> </Route>);
User 1234 is available at /user/1234
Multiple paramsimport { Route } from 'react-router';
const routes = ( <Route handler={App} path="/"> <Route name="users" handler={Users}> <Route name="user-message" path="/user/:userId/message/:messageId" handler={User} /> </Route> </Route>);
Example /users/123/message/456
Redirect routesimport { Route, Redirect } from 'react-router';
const routes = ( <Route handler={App} path="/"> <Route name="about" handler={About} /> <Redirect from="company" to="about" /> </Route>);
/company will be redirected to /about
Redirect routes with paramsimport { Route, Redirect } from 'react-router';
const routes = ( <Route handler={App} path="/"> <Redirect from="/user/me" to="user" params={{userId: MY_ID}} /> <Route name="user" path="/user/:userId" handler={User} /> </Route>);
Notice the order of the routes
Without nestingimport { Route, Redirect } from 'react-router';
const routes = [ <Route name="about" handler={About} />, <Route name="contact" handler={Contact} />];
Array of routes
Include external routesimport { Route, Redirect } from 'react-router';import aboutRoutes from 'about/routes';
const routes = { <Route handler={App} path="/"> <Redirect from="/user/me" to="user" params={{userId: MY_ID}} /> <Route name="user" path="/user/:userId" handler={User} /> {aboutRoutes} </Route>};
Running the router
Using hashesimport React from 'react';import Router from 'react-router';
Router.run(routes, (Handler) => { React.render(<Handler/>, document.body);});
Location will be http://localhost/#/about etc.
Using HTML5 Historyimport React from 'react';import Router from 'react-router';
Router.run(routes, Router.HistoryLocation, (Handler) => { React.render(<Handler/>, document.body);});
Location will be http://localhost/about etc.
Using Universal Renderingimport React from 'react';import Router from 'react-router';
app.serve((req, res) => { Router.run(routes, req.path, function (Handler) { const html = React.renderToString(Handler); res.send(html); });});
Render html to the client
Rendering the routes
App componentimport React from 'react';import { RouterHandler } from 'react-router';
class App extends React.Component { render() { return ( <div> <h1>Hello World!</h1> <RouterHandler /> </div> ); }}
Use RouterHandler to render matched route
Access router methods
ES5import React from 'react';
var User = React.createClass({ contextTypes: { router: React.PropTypes.func },
render: function () { return <h1>Hello World</h1>; }}
Available in render self.context.router
ES6import React from 'react';
class User extends React.Component { render() { return <h1>Hello World</h1>; }}
User.contextTypes = { router: React.PropTypes.func};
Available in render self.context.router
ES7import React from 'react';
class User extends React.Component { static contextTypes = { router: React.PropTypes.func, }
render() { return <h1>Hello World</h1>; }}
Available in render self.context.router
Available router methods
Getting paramsimport React from 'react';
class User extends React.Component { static contextTypes = { router: React.PropTypes.func, }
render() { const user = this.context.router.getCurrentParams().userId; return <h1>Hello user {user}</h1>; }}
From route /user/:userId
Getting query paramsimport React from 'react';
class User extends React.Component { static contextTypes = { router: React.PropTypes.func, }
render() { const message = this.context.router.getCurrentQuery().message; return <h1>{message}</h1>; }}
From url /user/1234?message=Hello%20World
Getting current routesimport React from 'react';
class User extends React.Component { static contextTypes = { router: React.PropTypes.func, }
render() { const routes = this.context.router.getCurrentRoutes(); ... }}
Array of routes in nesting order
Fetching dataimport React from 'react';import Router from 'react-router';
Router.run(routes, (Handler, state) => { fetchData(state).then(() => { React.render(<Handler/>, document.body); });});
Fetching datafunction fetchData(state) { return Promise.all(state.routes.filter((route) => { return route.handler.fetchData; }).map((route) => { return route.handler.fetchData(state.params, state.query); });}
Fetching dataimport React from 'react';
class User extends React.Component { static fetchData(params) { return new Promise((resolve) => { MyApi.loadSomething(() => { resolve(); }); }); } ...}
isActive methodimport React from 'react';
class Tab extends React.Component { static contextTypes = { router: React.PropTypes.func, }
render() { const isActive = this.isActive(this.props.to); const className = isActive ? 'active' : ''; return <li className={className}><Link {...this.props} />; }}
Call with <Tab to="about">About</Tab>
Navigating between routes
Using hrefimport React from 'react';
class User extends React.Component { render() { return ( <a href="/about">About</a> ); }}
Don't use this!
Using Link Componentimport React from 'react';import { Link } from 'react-router';
class User extends React.Component { render() { return ( <Link to="about">About</Link> ); }}
Will generate <a href="/about">About</a>
Using Link Componentimport React from 'react';import { Link } from 'react-router';
class About extends React.Component { render() { return ( <Link to="user" params={{userId: 1234}}>User 1234</Link> ); }}
With params
Using Link Componentimport React from 'react';import { Link } from 'react-router';
class About extends React.Component { render() { return ( <Link to="contact" query={{message: 'Hi'}}>Say hi</Link> ); }}
Will generate /contact?message=Hi
Using makeHrefimport React from 'react';
class User extends React.Component { static contextTypes = { router: React.PropTypes.func, }
render() { const link = this.context.router.makeHref('about'); return ( <a href={link}>About</a> ); }}
Using makeHrefimport React from 'react';
class About extends React.Component { static contextTypes = { router: React.PropTypes.func, }
render() { const link = this.context.router.makeHref('user', { userId: 1234 }, { message: 'Hi'}); return ( <a href={link}>About</a> ); }}
With params and query params
Using transitionToimport React from 'react';
class User extends React.Component { static contextTypes = { router: React.PropTypes.func, }
onSubmit() { this.context.router.transitionTo('about'); } ...}
Will transition to /about
Using transitionToimport React from 'react';
class About extends React.Component { static contextTypes = { router: React.PropTypes.func, }
onSubmit() { this.context.router.transitionTo('user', {userId: 1234}); } ...}
Will transition to /user/1234
Using transitionToimport React from 'react';
class About extends React.Component { static contextTypes = { router: React.PropTypes.func, }
onSubmit() { this.context.router.transitionTo('contact', {}, {message: 'Hi'}); } ...}
Will transition to /contact?message=Hi
Using replaceWithimport React from 'react';
class User extends React.Component { static contextTypes = { router: React.PropTypes.func, }
onSubmit() { this.context.router.replaceWith('about'); } ...}
Not added to browser history
Using goBackimport React from 'react';
class About extends React.Component { static contextTypes = { router: React.PropTypes.func, }
onClick() { this.context.router.goBack(); } ...}
Go back one step in history
goForwardimport React from 'react';
class About extends React.Component { static contextTypes = { router: React.PropTypes.func, }
onClick() { this.context.router.goForward(); } ...}
Go forward one step in history
go(n)import React from 'react';
class About extends React.Component { static contextTypes = { router: React.PropTypes.func, }
onClick() { this.context.router.go(2); } ...}
Go forward two steps in history
go(-n)import React from 'react';
class About extends React.Component { static contextTypes = { router: React.PropTypes.func, }
onClick() { this.context.router.go(-2); } ...}
Go backward two steps in history
Lifecycle methods
willTransitionToimport React from 'react';
class User extends React.Component { static willTransitionTo(transition) { if (!auth.loggedIn()) { transition.redirect('/login', {}, {'redirect' : transition.path}); } } ...}
willTransitionFromimport React from 'react';
class User extends React.Component { static willTransitionFrom(transition) { if (!form.validate()) { transition.abort(); } } ...}
Changes in 1.0
Handler to componentimport { Route } from 'react-router';
const routes = ( <Route handler={App} path="/"> <Route name="about" handler={About} /> </Route>);
...
const routes = ( <Route component={App} path="/"> <Route path="about" component={About} /> </Route>);
RouterHandler to propsclass App extends React.Component { render() { return ( <RouterHandler /> ); }}
class App extends React.Component { render() { return ( {this.props.children} ); }}
No more named routes<Route handler={App} path="/"> <Route name="user" path="/user/:userId" handler={User} /></Route>
...
<Route component={App} path="/"> <Route path="/user/:userId" component={User} /></Route>
Not found route<NotFoundRoute handler={NotFound} />
...
<Route path="*" component={NotFound} />
Catch all
Redirect routes<Route handler={App} path="/"> <Redirect from="/user/me" to="user" params={userId: '1234'} /> <Route name="user" path="/user/:userId" handler={User} /></Route>
...
<Route component={App} path="/"> <Redirect from="/user/me" to="/user/1234" /> <Route path="/user/:userId" component={User} /></Route>
Params in the url
Default route<Route handler={App} path="/"> <DefaultRoute handler={Home} /> <Route name="about" handler={About} /></Route>
...
<Route component={App} path="/"> <IndexRoute component={Home} /> <Route path="about" component={About} /></Route>
Home is available at /
Multiple componentsimport { Route } from 'react-router';
const routes = ( <Route component={App}> <Route path="users" components={{main: Users, sidebar: UsersSidebar}}/> </Route>);
Multiple componentsimport React from 'react';
class App extends React.Component { render() { return ( <div> <div className="Main"> {this.props.main} </div> <div className="Sidebar"> {this.props.sidebar} </div> </div> ); }}
Running the routerRouter.run(routes, (Handler) => { React.render(<Handler/>, document.body);});
...
import { history } from 'react-router/lib/HashHistory';
React.render(( <Router history={history}> {routes} </Router>), document.body);
History optionsimport { history } from 'react-router/lib/HashHistory';
import { history } from 'react-router/lib/BrowserHistory';
import { history } from 'react-router/lib/MemoryHistory';
Using makeHrefconst link = this.context.router.makeHref('user', { userId: 1234 }, { message: 'Hi'});
...
const link = this.context.router.createHref('/user/1234', { message: 'Hi'});
Params in the link
Link component<Link to="user" params={{userId: MY_ID}}>John Do</Link>
...
<Link to={'/users/' + MY_ID}>John Do</Link>
Params in the link
transitionTothis.context.router.transitionTo(pathname, params, query)this.context.router.transitionTo('user', { userId: 1234 }, { message: 'Hi' });
...
this.context.router.transitionTo(pathname, query, state)this.context.router.transitionTo('/user/1234', { message: 'Hi' });
willTransitionTo to onEnterclass User extends React.Component { static willTransitionTo(transition) { ... }}___
function requireAuth(nextState, transition) { ...}
const routes = ( <Route component={App} path="/"> <Route path="about" component={About} onEnter={requireAuth} /> </Route>);
willTransitionFrom to onLeaveclass User extends React.Component { static willTransitionFrom(transition) { ... }}___
function handler(nextState, transition) { ...}
const routes = ( <Route component={App} path="/"> <Route path="about" component={About} onLeave={handler} /> </Route>);
routerWillLeaveclass User extends React.Component { static willTransitionFrom(transition) { ... } ...}
class User extends React.Component { static routerWillLeave(nextState, router) { ... } ...}
Statestatic contextTypes = { router: React.PropTypes.func,}
render() { const user = this.context.router.getCurrentParams().userId;}___
static contextTypes: { location: React.Proptypes.object}
render() { const user = this.context.params.userId;}
State on routing componentclass User extends React.Component { render() { const location = this.props.location; const params = this.props.params; const history = this.props.history; ... }}
State0.x 1.x
getPath() location.pathname +location.query
getPathname() location.pathname
getParams() params
getQuery() location.query
getRoutes() routes
isActive(to, params,query)
history.isActive(pathname,query)
Questions?slideshare.net/robgietema