RouterContext
- Routerは必要なmethodやstate, propsなどの値を保持して、RouterContextをrenderする
- 実際に描画されるのはRouterContextである
const RouterContext = React.createClass({
...,
getDefaultProps() {
return {
createElement: React.createElement
}
},
...,
childContextTypes: {
history: object,
location: object.isRequired,
router: object.isRequired
},
getChildContext() {
let { router, history, location } = this.props
if (!router) {
warning(false, '`<RouterContext>` expects a `router` rather than a `history`')
router = {
...history,
setRouteLeaveHook: history.listenBeforeLeavingRoute
}
delete router.listenBeforeLeavingRoute
}
if (__DEV__) {
location = deprecateObjectProperties(location, '`context.location` is deprecated, please use a route component\'s `props.location` instead. http://tiny.cc/router-accessinglocation')
}
return { history, location, router }
},
...,
render() {
const { history, location, routes, params, components } = this.props
let element = null
if (components) {
element = components.reduceRight((element, components, index) => {
if (components == null)
return element // Don't create new children; use the grandchildren.
const route = routes[index]
const routeParams = getRouteParams(route, params)
const props = {
history,
location,
params,
route,
routeParams,
routes
}
if (isReactChildren(element)) {
props.children = element
} else if (element) {
for (const prop in element)
if (Object.prototype.hasOwnProperty.call(element, prop))
props[prop] = element[prop]
}
if (typeof components === 'object') {
const elements = {}
for (const key in components) {
if (Object.prototype.hasOwnProperty.call(components, key)) {
// Pass through the key as a prop to createElement to allow
// custom createElement functions to know which named component
// they're rendering, for e.g. matching up to fetched data.
elements[key] = this.createElement(components[key], {
key, ...props
})
}
}
return elements
}
return this.createElement(components, props)
}, element)
}
invariant(
element === null || element === false || React.isValidElement(element),
'The root route must render a single element'
)
return element
}
})
この4つが組み込みのmethodとなります。
呼ばれる順番は、childContextTypes -> getDefaultProps -> render -> getChildContextとなります。
childContextTypes, getDefaultPropsは値を詰めているだけなので、renderを見に行きます。
const { history, location, routes, params, components } = this.props
値が詰められるのは、history, routesとなります。
if (components) {
...,
}
この時点でcomponentsはnullのように思えます。
しかし、実はRoute.jsの中でhistory.listenが呼ばれています。
この時点でhistoryのルートURLに対してpopstatepushstateイベントが発生しています。
厳密には、'/'にアクセスすると、サーバはだいたい'index.html'を返すので、そこからjsが読み込まれて、'/'がpushstateされて、setState(state, callback)が呼ばれているようです。
試しに、index.html以外から呼び出すと、何も表示されていませんでした。
index.html以外でも表示されるのかは調査が必要ですね。
なので、一度Router.jsまで遡り、componentsが何なのかを見ていきます。