React Router: React Meetup XXL

  • View
    1.363

  • Download
    1

  • Category

    Internet

Preview:

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