-
-
Notifications
You must be signed in to change notification settings - Fork 10.4k
/
Copy pathRouter.js
149 lines (124 loc) · 4.46 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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
import createHashHistory from 'history/lib/createHashHistory'
import useQueries from 'history/lib/useQueries'
import React from 'react'
import createTransitionManager from './createTransitionManager'
import { routes } from './PropTypes'
import RouterContext from './RouterContext'
import { createRoutes } from './RouteUtils'
import { createRouterObject, createRoutingHistory } from './RouterUtils'
import warning from './warning'
function isDeprecatedHistory(history) {
return !history || !history.__v2_compatible__
}
const { func, object } = React.PropTypes
/**
* A <Router> is a high-level API for automatically setting up
* a router that renders a <RouterContext> with all the props
* it needs each time the URL changes.
*/
const Router = React.createClass({
propTypes: {
history: object,
children: routes,
routes, // alias for children
render: func,
createElement: func,
onError: func,
onUpdate: func
},
getDefaultProps() {
return {
render(props) {
return <RouterContext {...props} />
}
}
},
getInitialState() {
// Use initial state from renderProps when available, to allow using match
// on client side when doing server-side rendering.
const { location, routes, params, components } = this.props
return { location, routes, params, components }
},
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 } = this.props
const { routes, children } = this.props
const { parseQueryString, stringifyQuery } = this.props
warning(
!(parseQueryString || stringifyQuery),
'`parseQueryString` and `stringifyQuery` are deprecated. Please create a custom history. http://tiny.cc/router-customquerystring'
)
if (isDeprecatedHistory(history)) {
history = this.wrapDeprecatedHistory(history)
}
const transitionManager = createTransitionManager(
history, createRoutes(routes || children)
)
this._unlisten = transitionManager.listen((error, state) => {
if (error) {
this.handleError(error)
} else {
this.setState(state, this.props.onUpdate)
}
})
this.router = createRouterObject(history, transitionManager)
this.history = createRoutingHistory(history, transitionManager)
},
wrapDeprecatedHistory(history) {
const { parseQueryString, stringifyQuery } = this.props
let createHistory
if (history) {
warning(false, 'It appears you have provided a deprecated history object to `<Router/>`, please use a history provided by ' +
'React Router with `import { browserHistory } from \'react-router\'` or `import { hashHistory } from \'react-router\'`. ' +
'If you are using a custom history please create it with `useRouterHistory`, see http://tiny.cc/router-usinghistory for details.')
createHistory = () => history
} else {
warning(false, '`Router` no longer defaults the history prop to hash history. Please use the `hashHistory` singleton instead. http://tiny.cc/router-defaulthistory')
createHistory = createHashHistory
}
return useQueries(createHistory)({ parseQueryString, stringifyQuery })
},
/* istanbul ignore next: sanity check */
componentWillReceiveProps(nextProps) {
warning(
nextProps.history === this.props.history,
'You cannot change <Router history>; it will be ignored'
)
warning(
(nextProps.routes || nextProps.children) ===
(this.props.routes || this.props.children),
'You cannot change <Router routes>; it will be ignored'
)
},
componentWillUnmount() {
if (this._unlisten)
this._unlisten()
},
render() {
const { location, routes, params, components } = this.state
const { createElement, render, ...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 render({
...props,
history: this.history,
router: this.router,
location,
routes,
params,
components,
createElement
})
}
})
export default Router