LoginSignup
4
4

More than 5 years have passed since last update.

React Routerは何をしているのか? ~RouterContext編~

Last updated at Posted at 2016-03-22

RouterContext

  • Routerは必要なmethodやstate, propsなどの値を保持して、RouterContextをrenderする
  • 実際に描画されるのはRouterContextである
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を見に行きます。

render
    const { history, location, routes, params, components } = this.props

値が詰められるのは、history, routesとなります。

render
    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が何なのかを見ていきます。

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4