/
Router.js
110 lines (92 loc) · 2.7 KB
/
Router.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import warning from 'warning'
import React, { Component } from 'react'
import createHashHistory from 'history/lib/createHashHistory'
import { createRoutes } from './RouteUtils'
import RoutingContext from './RoutingContext'
import useRoutes from './useRoutes'
import { routes } from './PropTypes'
const { func, object } = React.PropTypes
/**
* A <Router> is a high-level API for automatically setting up
* a router that renders a <RoutingContext> with all the props
* it needs each time the URL changes.
*/
class Router extends Component {
static propTypes = {
history: object,
children: routes,
routes, // alias for children
RoutingContext: func.isRequired,
createElement: func,
onError: func,
onUpdate: func,
parseQueryString: func,
stringifyQuery: func
}
static defaultProps = {
RoutingContext
}
constructor(props, context) {
super(props, context)
this.state = {
location: null,
routes: null,
params: null,
components: null
}
}
handleError(error) {
if (this.props.onError) {
this.props.onError.call(this, error)
} else {
// Throw errors by default so we don't silently swallow them!
throw error // This error probably occurred in getChildRoutes or getComponents.
}
}
componentWillMount() {
let { history, children, routes, parseQueryString, stringifyQuery } = this.props
let createHistory = history ? () => history : createHashHistory
this.history = useRoutes(createHistory)({
routes: createRoutes(routes || children),
parseQueryString,
stringifyQuery
})
this._unlisten = this.history.listen((error, state) => {
if (error) {
this.handleError(error)
} else {
this.setState(state, this.props.onUpdate)
}
})
}
/* istanbul ignore next: sanity check */
componentWillReceiveProps(nextProps) {
warning(
nextProps.history === this.props.history,
'You cannot change <Router history>; it will be ignored'
)
}
componentWillUnmount() {
if (this._unlisten)
this._unlisten()
}
render() {
let { location, routes, params, components } = this.state
let { RoutingContext, createElement, ...props } = this.props
if (location == null)
return null // Async match
// Only forward non-Router-specific props to routing context, as those are
// the only ones that might be custom routing context props.
Object.keys(Router.propTypes).forEach(propType => delete props[propType])
return React.createElement(RoutingContext, {
...props,
history: this.history,
createElement,
location,
routes,
params,
components
})
}
}
export default Router