all files / modules/ Router.js

96.26% Statements 103/107
91.3% Branches 42/46
94.44% Functions 17/18
80.95% Lines 17/21
11 statements, 2 functions, 16 branches Ignored     
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                                                                75×   75×                                     75×   75×           75× 84×     84×                         65× 65×             86×       84×   84×                              
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) => {
      Iif (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() {
    Eif (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