Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/react-router-website/modules/components/Examples.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ const EXAMPLES = [
path: '/examples/route-config',
load: require('bundle?lazy!babel!../examples/RouteConfig'),
loadSource: require('bundle?lazy!!prismjs?lang=jsx!../examples/RouteConfig.js')
},
{ name: 'Modal Gallery',
path: '/examples/modal-gallery',
load: require('bundle?lazy!babel!../examples/ModalGallery'),
loadSource: require('bundle?lazy!!prismjs?lang=jsx!../examples/ModalGallery.js')
}
]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class FakeBrowser extends React.Component {

return (
<MemoryRouter getUserConfirmation={getUserConfirmation}>
<Route render={({ canGo, goBack, goForward, push, location }) => (
<Route render={({ history, location }) => (
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to fix a few things in the examples to get them working with the new { match, location, history } props.

<V
className="fake-browser"
background="white"
Expand All @@ -78,10 +78,10 @@ class FakeBrowser extends React.Component {
borderBottom="solid 1px #ccc"
padding={`0 ${PAD / 2}px`}
>
<Button onClick={goBack} disabled={!canGo(-1)}>
<Button onClick={history.goBack} disabled={!history.canGo(-1)}>
<LeftArrowIcon height="1em" width="1em" style={{ verticalAlign: 'middle', marginTop: -3 }}/>
</Button>
<Button onClick={goForward} disabled={!canGo(1)}>
<Button onClick={history.goForward} disabled={!history.canGo(1)}>
<RightArrowIcon height="1em" width="1em" style={{ verticalAlign: 'middle', marginTop: -3 }}/>
</Button>
<B
Expand Down Expand Up @@ -114,7 +114,7 @@ class FakeBrowser extends React.Component {
onKeyDown: (e) => {
if (e.key === 'Enter') {
this.setState({ url: null })
push(e.target.value)
history.push(e.target.value)
}
}
}}
Expand Down
4 changes: 2 additions & 2 deletions packages/react-router-website/modules/examples/Auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ const fakeAuth = {
}
}

const AuthButton = withRouter(({ push }) => (
const AuthButton = withRouter(({ history }) => (
fakeAuth.isAuthenticated ? (
<p>
Welcome! <button onClick={() => {
fakeAuth.signout(() => push('/'))
fakeAuth.signout(() => history.push('/'))
}}>Sign out</button>
</p>
) : (
Expand Down
151 changes: 151 additions & 0 deletions packages/react-router-website/modules/examples/ModalGallery.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import React from 'react'
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from 'react-router-dom'


const IMAGES = [
{ id: 0, title: 'Dark Orchid', color: 'DarkOrchid' },
{ id: 1, title: 'Lime Green', color: 'LimeGreen' },
{ id: 2, title: 'Gold', color: 'Gold' },
{ id: 3, title: 'Midnight Blue', color: 'MidnightBlue' },
{ id: 4, title: 'Dark Slate Gray', color: 'DarkSlateGray' },
{ id: 5, title: 'Tomato', color: 'Tomato' },
{ id: 6, title: 'Seven Ate Nine', color: '#789' },
{ id: 7, title: 'Olive Drab', color: 'OliveDrab' },
{ id: 8, title: 'Crimson', color: 'Crimson' },
{ id: 9, title: 'Sea Green', color: 'SeaGreen' }
]

const Thumbnail = ({ color }) =>
<div style={{ width: 50, height: 50, background: color }}></div>

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/5'>Tomato</Link></li>
<li><Link to='/img/9'>Sea Green</Link></li>
</ul>
</div>
)

const Gallery = () => (
<div>
{
IMAGES.map(i => (
<Link
key={i.id}
to={{ pathname: `/img/${i.id}`, 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>
)
}

class ModalSwitch extends React.Component {

componentWillMount() {
// set the initial previousLocation value on mount
this.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
)
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 ModalGallery = () => (
<Router>
<Route component={ModalSwitch} />
</Router>
)

export default ModalGallery
19 changes: 10 additions & 9 deletions packages/react-router/modules/Route.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import matchPath from './matchPath'
*/
class Route extends React.Component {
static contextTypes = {
history: PropTypes.object.isRequired
history: PropTypes.object.isRequired,
route: PropTypes.object.isRequired
}

static propTypes = {
Expand All @@ -31,26 +32,26 @@ class Route extends React.Component {
getChildContext() {
return {
route: {
location: this.props.location || this.context.history.location,
location: this.props.location || this.context.route.location,
match: this.state.match
}
}
}

state = {
match: this.computeMatch(this.props)
match: this.computeMatch(this.props, this.context)
}

computeMatch({ computedMatch, location, path, strict, exact }) {
computeMatch({ computedMatch, location, path, strict, exact }, { route }) {
if (computedMatch)
return computedMatch // <Switch> already computed the match for us

const pathname = (location || this.context.history.location).pathname
const pathname = (location || route.location).pathname

return matchPath(pathname, { path, strict, exact })
}

componentWillReceiveProps(nextProps) {
componentWillReceiveProps(nextProps, nextContext) {
warning(
!(nextProps.location && !this.props.location),
'<Route> elements should not change from uncontrolled to controlled (or vice versa). You initially used no "location" prop and then provided one on a subsequent render.'
Expand All @@ -62,15 +63,15 @@ class Route extends React.Component {
)

this.setState({
match: this.computeMatch(nextProps)
match: this.computeMatch(nextProps, nextContext)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to use the next context object here. Otherwise when there is no location prop, the previous location will be used when computing the new match.

})
}

render() {
const { match } = this.state
const { children, component, render } = this.props
const { history } = this.context
const { location } = history
const { history, route } = this.context
const location = this.props.location || route.location
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just making sure that the component rendered by the route receives the correct location.

const props = { match, location, history }

return (
Expand Down
1 change: 1 addition & 0 deletions packages/react-router/modules/Router.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class Router extends React.Component {
return {
history: this.props.history,
route: {
location: this.props.history.location,
match: this.state.match
}
}
Expand Down
6 changes: 3 additions & 3 deletions packages/react-router/modules/Switch.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import matchPath from './matchPath'
*/
class Switch extends React.Component {
static contextTypes = {
history: PropTypes.object.isRequired
route: PropTypes.object.isRequired
}

static propTypes = {
Expand All @@ -29,7 +29,7 @@ class Switch extends React.Component {

render() {
const { children } = this.props
const location = this.props.location || this.context.history.location
const location = this.props.location || this.context.route.location

let match, child
React.Children.forEach(children, element => {
Expand All @@ -39,7 +39,7 @@ class Switch extends React.Component {
}
})

return match ? React.cloneElement(child, { computedMatch: match }) : null
return match ? React.cloneElement(child, { location, computedMatch: match }) : null
}
}

Expand Down
Loading