import React from 'react'
import {
BrowserRouter as Router,
Route,
Link,
Switch
} from 'react-router-dom'
const AmbiguousExample = () => (
<Router>
<div>
<ul>
<li><Link to="/about">About Us (static)</Link></li>
<li><Link to="/company">Company (static)</Link></li>
<li><Link to="/kim">Kim (dynamic)</Link></li>
<li><Link to="/chris">Chris (dynamic)</Link></li>
</ul>
{/*
Sometimes you want to have a whitelist of static paths
like "/about" and "/company" but also allow for dynamic
patterns like "/:user". The problem is that "/about"
is ambiguous and will match both "/about" and "/:user".
Most routers have an algorithm to decide for you what
it will match since they only allow you to match one
"route". React Router lets you match in multiple places
on purpose (sidebars, breadcrumbs, etc). So, when you
want to clear up any ambiguous matching, and not match
"/about" to "/:user", just wrap your <Route>s in a
<Switch>. It will render the first one that matches.
*/}
<Switch>
<Route path="/about" component={About}/>
<Route path="/company" component={Company}/>
<Route path="/:user" component={User}/>
</Switch>
</div>
</Router>
)
const About = () => <h2>About</h2>
const Company = () => <h2>Company</h2>
const User = ({ match }) => (
<div>
<h2>User: {match.params.user}</h2>
</div>
)
export default AmbiguousExample
2.AnimationExample
import React from 'react'
import ReactCSSTransitionGroup from 'react-addons-css-transition-group'
import {
BrowserRouter as Router,
Route,
Link,
Redirect
} from 'react-router-dom'
/* you'll need this CSS somewhere
.fade-enter {
opacity: 0;
z-index: 1;
}
.fade-enter.fade-enter-active {
opacity: 1;
transition: opacity 250ms ease-in;
}
*/
const AnimationExample = () => (
<Router>
<Route render={({ location }) => (
<div style={styles.fill}>
<Route exact path="/" render={() => (
<Redirect to="/10/90/50"/>
)}/>
<ul style={styles.nav}>
<NavLink to="/10/90/50">Red</NavLink>
<NavLink to="/120/100/40">Green</NavLink>
<NavLink to="/200/100/40">Blue</NavLink>
<NavLink to="/310/100/50">Pink</NavLink>
</ul>
<div style={styles.content}>
<ReactCSSTransitionGroup
transitionName="fade"
transitionEnterTimeout={300}
transitionLeaveTimeout={300}
>
{/* no different than other usage of
ReactCSSTransitionGroup, just make
sure to pass `location` to `Route`
so it can match the old location
as it animates out
*/}
<Route
location={location}
key={location.key}
path="/:h/:s/:l"
component={HSL}
/>
</ReactCSSTransitionGroup>
</div>
</div>
)}/>
</Router>
)
const NavLink = (props) => (
<li style={styles.navItem}>
<Link {...props} style={{ color: 'inherit' }}/>
</li>
)
const HSL = ({ match: { params } }) => (
<div style={{
...styles.fill,
...styles.hsl,
background: `hsl(${params.h}, ${params.s}%, ${params.l}%)`
}}>hsl({params.h}, {params.s}%, {params.l}%)</div>
)
const styles = {}
styles.fill = {
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0
}
styles.content = {
...styles.fill,
top: '40px',
textAlign: 'center'
}
styles.nav = {
padding: 0,
margin: 0,
position: 'absolute',
top: 0,
height: '40px',
width: '100%',
display: 'flex'
}
styles.navItem = {
textAlign: 'center',
flex: 1,
listStyleType: 'none',
padding: '10px'
}
styles.hsl = {
...styles.fill,
color: 'white',
paddingTop: '20px',
fontSize: '30px'
}
export default AnimationExample
3.AuthExample
import React, { PropTypes } from 'react'
import {
BrowserRouter as Router,
Route,
Link,
Redirect,
withRouter
} from 'react-router-dom'
// 1. Click the public page
// 2. Click the protected page
// 3. Log in
// 4. Click the back button, note the URL each time
const AuthExample = () => (
<Router>
<div>
<AuthButton/>
<ul>
<li><Link to="/public">Public Page</Link></li>
<li><Link to="/protected">Protected Page</Link></li>
</ul>
<Route path="/public" component={Public}/>
<Route path="/login" component={Login}/>
<PrivateRoute path="/protected" component={Protected}/>
</div>
</Router>
)
const fakeAuth = {
isAuthenticated: false,
authenticate(cb) {
this.isAuthenticated = true
setTimeout(cb, 100) // fake async
},
signout(cb) {
this.isAuthenticated = false
setTimeout(cb, 100)
}
}
const AuthButton = withRouter(({ history }) => (
fakeAuth.isAuthenticated ? (
<p>
Welcome! <button onClick={() => {
fakeAuth.signout(() => history.push('/'))
}}>Sign out</button>
</p>
) : (
<p>You are not logged in.</p>
)
))
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={props => (
fakeAuth.isAuthenticated ? (
<Component {...props}/>
) : (
<Redirect to={{
pathname: '/login',
state: { from: props.location }
}}/>
)
)}/>
)
const Public = () => <h3>Public</h3>
const Protected = () => <h3>Protected</h3>
class Login extends React.Component {
state = {
redirectToReferrer: false
}
login = () => {
fakeAuth.authenticate(() => {
this.setState({ redirectToReferrer: true })
})
}
render() {
const { from } = this.props.location.state || { from: { pathname: '/' } }
const { redirectToReferrer } = this.state
if (redirectToReferrer) {
return (
<Redirect to={from}/>
)
}
return (
<div>
<p>You must log in to view the page at {from.pathname}</p>
<button onClick={this.login}>Log in</button>
</div>
)
}
}
export default AuthExample
4.BasicExample
import React from 'react'
import {
BrowserRouter as Router,
Route,
Link
} from 'react-router-dom'
const BasicExample = () => (
<Router>
<div>
<ul>
<li><Link to="/">首页</Link></li>
<li><Link to="/about">关于</Link></li>
<li><Link to="/topics">主题列表</Link></li>
</ul>
<hr/>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
<Route path="/topics" component={Topics}/>
</div>
</Router>
)
const Home = () => (
<div>
<h2>首页</h2>
</div>
)
const About = () => (
<div>
<h2>关于</h2>
</div>
)
const Topics = ({ match }) => (
<div>
<h2>主题列表</h2>
<ul>
<li>
<Link to={`${match.url}/rendering`}>
使用 React 渲染
</Link>
</li>
<li>
<Link to={`${match.url}/components`}>
组件
</Link>
</li>
<li>
<Link to={`${match.url}/props-v-state`}>
属性 v. 状态
</Link>
</li>
</ul>
<Route path={`${match.url}/:topicId`} component={Topic}/>
<Route exact path={match.url} render={() => (
<h3>请选择一个主题。</h3>
)}/>
</div>
)
const Topic = ({ match }) => (
<div>
<h3>{match.params.topicId}</h3>
</div>
)
export default BasicExample
5.CustomLinkExample
import React from 'react'
import {
BrowserRouter as Router,
Route,
Link
} from 'react-router-dom'
const CustomLinkExample = () => (
<Router>
<div>
<OldSchoolMenuLink activeOnlyWhenExact={true} to="/" label="Home"/>
<OldSchoolMenuLink to="/about" label="About"/>
<hr/>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
</div>
</Router>
)
const OldSchoolMenuLink = ({ label, to, activeOnlyWhenExact }) => (
<Route path={to} exact={activeOnlyWhenExact} children={({ match }) => (
<div className={match ? 'active' : ''}>
{match ? '> ' : ''}<Link to={to}>{label}</Link>
</div>
)}/>
)
const Home = () => (
<div>
<h2>Home</h2>
</div>
)
const About = () => (
<div>
<h2>About</h2>
</div>
)
export default CustomLinkExample
6.ModalGallery
import React from 'react'
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from 'react-router-dom'
// This example shows how to render two different screens
// (or the same screen in a different context) at the same url,
// depending on you got there.
//
// Click the colors and see them full screen, then "visit the
// gallery" and click on the colors. Note the URL and the component
// are the same as before but now we see them inside a modal
// on top of the old screen.
class ModalSwitch extends React.Component {
// We can pass a location to <Switch/> that will tell it to
// ignore the router's current location and use the location
// prop instead.
//
// We can also use "location state" to tell the app the user
// wants to go to `/images/2` in a modal, rather than as the
// main page, keeping the gallery visible behind it.
//
// Normally, `/images/2` wouldn't match the gallery at `/`.
// So, to get both screens to render, we can save the old
// location and pass it to Switch, so it will think the location
// is still `/` even though its `/images/2`.
previousLocation = this.props.location
componentWillUpdate(nextProps) {
const { location } = this.props
// set previousLocation if props.location is not modal
if (
nextProps.history.action !== 'POP' &&
(!location.state || !location.state.modal)
) {
this.previousLocation = this.props.location
}
}
render() {
const { location } = this.props
const isModal = !!(
location.state &&
location.state.modal &&
this.previousLocation !== location // not initial render
)
return (
<div>
<Switch location={isModal ? this.previousLocation : location}>
<Route exact path='/' component={Home}/>
<Route path='/gallery' component={Gallery}/>
<Route path='/img/:id' component={ImageView}/>
</Switch>
{isModal ? <Route path='/img/:id' component={Modal} /> : null}
</div>
)
}
}
const IMAGES = [
{ id: 0, title: 'Dark Orchid', color: 'DarkOrchid' },
{ id: 1, title: 'Lime Green', color: 'LimeGreen' },
{ id: 2, title: 'Tomato', color: 'Tomato' },
{ id: 3, title: 'Seven Ate Nine', color: '#789' },
{ id: 4, title: 'Crimson', color: 'Crimson' }
]
const Thumbnail = ({ color }) =>
<div style={{
width: 50,
height: 50,
background: color
}}/>
const Image = ({ color }) =>
<div style={{
width: '100%',
height: 400,
background: color
}}></div>
const Home = () => (
<div>
<Link to='/gallery'>Visit the Gallery</Link>
<h2>Featured Images</h2>
<ul>
<li><Link to='/img/2'>Tomato</Link></li>
<li><Link to='/img/4'>Crimson</Link></li>
</ul>
</div>
)
const Gallery = () => (
<div>
{IMAGES.map(i => (
<Link
key={i.id}
to={{
pathname: `/img/${i.id}`,
// this is the trick!
state: { modal: true }
}}
>
<Thumbnail color={i.color} />
<p>{i.title}</p>
</Link>
))}
</div>
)
const ImageView = ({ match }) => {
const image = IMAGES[parseInt(match.params.id, 10)]
if (!image) {
return <div>Image not found</div>
}
return (
<div>
<h1>{image.title}</h1>
<Image color={image.color} />
</div>
)
}
const Modal = ({ match, history }) => {
const image = IMAGES[parseInt(match.params.id, 10)]
if (!image) {
return null
}
const back = (e) => {
e.stopPropagation()
history.goBack()
}
return (
<div
onClick={back}
style={{
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
right: 0,
background: 'rgba(0, 0, 0, 0.15)'
}}
>
<div className='modal' style={{
position: 'absolute',
background: '#fff',
top: 25,
left: '10%',
right: '10%',
padding: 15,
border: '2px solid #444'
}}>
<h1>{image.title}</h1>
<Image color={image.color} />
<button type='button' onClick={back}>
Close
</button>
</div>
</div>
)
}
const ModalGallery = () => (
<Router>
<Route component={ModalSwitch} />
</Router>
)
export default ModalGallery
7.NoMatchExample
import React from 'react'
import {
BrowserRouter as Router,
Route,
Link,
Switch,
Redirect
} from 'react-router-dom'
const NoMatchExample = () => (
<Router>
<div>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/old-match">Old Match, to be redirected</Link></li>
<li><Link to="/will-match">Will Match</Link></li>
<li><Link to="/will-not-match">Will Not Match</Link></li>
<li><Link to="/also/will/not/match">Also Will Not Match</Link></li>
</ul>
<Switch>
<Route path="/" exact component={Home}/>
<Redirect from="/old-match" to="/will-match"/>
<Route path="/will-match" component={WillMatch}/>
<Route component={NoMatch}/>
</Switch>
</div>
</Router>
)
const Home = () => (
<p>
A <code><Switch></code> renders the
first child <code><Route></code> that
matches. A <code><Route></code> with
no <code>path</code> always matches.
</p>
)
const WillMatch = () => <h3>Matched!</h3>
const NoMatch = ({ location }) => (
<div>
<h3>No match for <code>{location.pathname}</code></h3>
</div>
)
export default NoMatchExample
8.ParamsExample
import React from 'react'
import {
BrowserRouter as Router,
Route,
Link
} from 'react-router-dom'
const ParamsExample = () => (
<Router>
<div>
<h2>账号</h2>
<ul>
<li><Link to="/react-router">React Router</Link></li>
<li><Link to="/leoashin">LeoAshin</Link></li>
<li><Link to="/justjavac">justjavac</Link></li>
<li><Link to="/reacttraining">React Training</Link></li>
</ul>
<Route path="/:id" component={Child}/>
</div>
</Router>
)
const Child = ({ match }) => (
<div>
<h3>ID: {match.params.id}</h3>
</div>
)
export default ParamsExample
9.PreventingTransitionsExample
import React from 'react'
import {
BrowserRouter as Router,
Route,
Link,
Prompt
} from 'react-router-dom'
const PreventingTransitionsExample = () => (
<Router>
<div>
<ul>
<li><Link to="/">Form</Link></li>
<li><Link to="/one">One</Link></li>
<li><Link to="/two">Two</Link></li>
</ul>
<Route path="/" exact component={Form}/>
<Route path="/one" render={() => <h3>One</h3>}/>
<Route path="/two" render={() => <h3>Two</h3>}/>
</div>
</Router>
)
class Form extends React.Component {
state = {
isBlocking: false
}
render() {
const { isBlocking } = this.state
return (
<form
onSubmit={event => {
event.preventDefault()
event.target.reset()
this.setState({
isBlocking: false
})
}}
>
<Prompt
when={isBlocking}
message={location => (
`Are you sure you want to go to ${location.pathname}`
)}
/>
<p>
Blocking? {isBlocking ? 'Yes, click a link or the back button' : 'Nope'}
</p>
<p>
<input
size="50"
placeholder="type something to block transitions"
onChange={event => {
this.setState({
isBlocking: event.target.value.length > 0
})
}}
/>
</p>
<p>
<button>Submit to stop blocking</button>
</p>
</form>
)
}
}
export default PreventingTransitionsExample
10.RecursiveExample.js
import React from 'react'
import {
BrowserRouter as Router,
Route,
Link
} from 'react-router-dom'
const PEEPS = [
{ id: 0, name: 'Michelle', friends: [ 1, 2, 3 ] },
{ id: 1, name: 'Sean', friends: [ 0, 3 ] },
{ id: 2, name: 'Kim', friends: [ 0, 1, 3 ], },
{ id: 3, name: 'David', friends: [ 1, 2 ] }
]
const find = (id) => PEEPS.find(p => p.id == id)
const RecursiveExample = () => (
<Router>
<Person match={{ params: { id: 0 }, url: '' }}/>
</Router>
)
const Person = ({ match }) => {
const person = find(match.params.id)
return (
<div>
<h3>{person.name}’s Friends</h3>
<ul>
{person.friends.map(id => (
<li key={id}>
<Link to={`${match.url}/${id}`}>
{find(id).name}
</Link>
</li>
))}
</ul>
<Route path={`${match.url}/:id`} component={Person}/>
</div>
)
}
export default RecursiveExample
11.RouteConfigExample
import React from 'react'
import {
BrowserRouter as Router,
Route,
Link
} from 'react-router-dom'
// Some folks find value in a centralized route config.
// A route config is just data. React is great at mapping
// data into components, and <Route> is a component.
// first our route components
const Main = () => <h2>Main</h2>
const Sandwiches = () => <h2>Sandwiches</h2>
const Tacos = ({ routes }) => (
<div>
<h2>Tacos</h2>
<ul>
<li><Link to="/tacos/bus">Bus</Link></li>
<li><Link to="/tacos/cart">Cart</Link></li>
</ul>
{routes.map((route, i) => (
<RouteWithSubRoutes key={i} {...route}/>
))}
</div>
)
const Bus = () => <h3>Bus</h3>
const Cart = () => <h3>Cart</h3>
// then our route config
const routes = [
{ path: '/sandwiches',
component: Sandwiches
},
{ path: '/tacos',
component: Tacos,
routes: [
{ path: '/tacos/bus',
component: Bus
},
{ path: '/tacos/cart',
component: Cart
}
]
}
]
// wrap <Route> and use this everywhere instead, then when
// sub routes are added to any route it'll work
const RouteWithSubRoutes = (route) => (
<Route path={route.path} render={props => (
// pass the sub-routes down to keep nesting
<route.component {...props} routes={route.routes}/>
)}/>
)
const RouteConfigExample = () => (
<Router>
<div>
<ul>
<li><Link to="/tacos">Tacos</Link></li>
<li><Link to="/sandwiches">Sandwiches</Link></li>
</ul>
{routes.map((route, i) => (
<RouteWithSubRoutes key={i} {...route}/>
))}
</div>
</Router>
)
export default RouteConfigExample
12.SidebarExample
import React from 'react'
import {BrowserRouter as Router,
Route,
Link
} from 'react-router-dom'
// Each logical "route" has two components, one for
// the sidebar and one for the main area. We want to
// render both of them in different places when the
// path matches the current URL.
const routes = [
{ path: '/',
exact: true,
sidebar: () => <div>home!</div>,
main: () => <h2>Home</h2>
},
{ path: '/bubblegum',
sidebar: () => <div>bubblegum!</div>,
main: () => <h2>Bubblegum</h2>
},
{ path: '/shoelaces',
sidebar: () => <div>shoelaces!</div>,
main: () => <h2>Shoelaces</h2>
}
]
const SidebarExample = () => (
<Router>
<div style={{ display: 'flex' }}>
<div style={{
padding: '10px',
width: '40%',
background: '#f0f0f0'
}}>
<ul style={{ listStyleType: 'none', padding: 0 }}>
<li><Link to="/">Home</Link></li>
<li><Link to="/bubblegum">Bubblegum</Link></li>
<li><Link to="/shoelaces">Shoelaces</Link></li>
</ul>
{routes.map((route, index) => (
// You can render a <Route> in as many places
// as you want in your app. It will render along
// with any other <Route>s that also match the URL.
// So, a sidebar or breadcrumbs or anything else
// that requires you to render multiple things
// in multiple places at the same URL is nothing
// more than multiple <Route>s.
<Route
key={index}
path={route.path}
exact={route.exact}
component={route.sidebar}
/>
))}
</div>
<div style={{ flex: 1, padding: '10px' }}>
{routes.map((route, index) => (
// Render more <Route>s with the same paths as
// above, but different components this time.
<Route
key={index}
path={route.path}
exact={route.exact}
component={route.main}
/>
))}
</div>
</div>
</Router>
)
export default SidebarExample