React-Router@4 结构图

2018-07-12

画了个 React-Router 架构图, 方便理解

+----------------------------------------------------------+
| BrowserRouter|HashRouter|MemoryRouter, 提供 history       |
|                                                          |
| createHistory =                                          |
|    history.createBrowserHistory /* hash|memory */        |
|                                                          |
| this.history = createHistory(this.props)                 |
|                                                          |
| render() {                                               |
|    return React.cloneElement(Router, {                   |
|        history: this.history,                            |
|        children: this.props.children                     |
|    })                                                    |
| }                                                        |
+----------------------------------------------------------+
      |                               |
      |                               |
      | <----  传入 props.history -->  |
      ↓               ↓               ↓
+-----------------------------------------------------------+
| Router, 根据传入的 history 提供 context api,                |
| 设置 history 的监听函数                                     |
|                                                           |
| state = {                                                 |
|    match: this.computeMatch(                              |
|      this.props.history.location.pathname                 |
|    )                                                      |
| }                                                         |
| // 提供 context                                            |
| getChildContext = () => {                                 |
|    return {                                               |
|        router: Object.assign({}, this.context.router, {   |
|            history: this.props.history,                   |
|            route: {                                       |
|                location: this.props.history.location,     |
|                match: this.state.match                    |
|            }                                              |
|        })                                                 |
|     }                                                     |
| }                                                         |
| computeMatch = (pathname) => {                            |
|    return {                                               |
|      path: "/",                                           |
|      url: "/",                                            |
|      params: {},                                          |
|      isExact: pathname === "/"                            |
|    };                                                     |
| }                                                         |
|                                                           |
| componentWillMount() {                                    |
|    this.props.history.listen(() => {                      |
|        //每次 url 更新 都会触发 setState 从而 render         |
|        //下面所有的 Route 组件也会 render                    |
|        this.setState({                                    |
|            match: this.computeMatch(                      |
|                this.props.history.location.pathname       |
|            )                                              |
|        })                                                 |
|    })                                                     |
| }                                                         |
| render() {                                                |
|    return React.Children.only(children)                   |
| }                                                         |
+-----------------------------------------------------------+
                            | Children
                            ↓
|-----------------------------------------------------------+
|  Route, 高阶组件, 渲染传入的 React 组件                       |
|                                                           |
|  state = {                                                |
|     match = this.computeMatch(                            |
|         this.props,                                       |
|         this.context.router                               |
|     )                                                     |
|  }                                                        |
|  // 返回 context 对象                                      |
|  getChildContext = () => {                                |
|    return {                                               |
|      router: Object.assign({}, this.context.router, {     |
|         route: {                                          |
|            location: this.props.location                  |
|              || this.context.router.route.location,       |
|             match: this.state.match                       |
|         }                                                 |
|       })                                                  |
|    };                                                     |
|  }                                                        |
|  componentWillReceiveProps() {                            |
|        this.setState({                                    |
|            match: this.computeMatch(                      |
|                nextProps,                                 |
|                nextContext.router                         |
|            )                                              |
|        });                                                |
|  }                                                        |
|  computeMatch = (_ref, router) => {                       |
|     var computedMatch = _ref.computedMatch,               |
|         location = _ref.location,                         |
|         path = _ref.path,                                 |
|         strict = _ref.strict,                             |
|         exact = _ref.exact,                               |
|         sensitive = _ref.sensitive;                       |
|     // 有这个属性, 说明路由经过了 Switch, 它只会匹配第一个       |
|     // 做法是标记是否匹配过 跟已经匹配到的 route,               |
|     // 一旦匹配到, 直接返回                                  |
|     if (computedMatch) return computedMatch;              |
|     var route = router.route;                             |
|                                                           |
|     var pathname = (location || route.location).pathname; |
|     return matchPath(                                     |
|         pathname,                                         |
|         {                                                 |
|             path: path, strict: strict,                   |
|             exact: exact, sensitive: sensitive            |
|         },                                                |
|         route.match                                       |
|     );                                                    |
|  }                                                        |
|  render() {                                               |
|        var component = this.props.component;              |
|        if (component) {                                   |
|            return match                                   |
|              ? React.createElement(component, this.props) |
|              : null;                                      |
|        }                                                  |
|        // 支持 Route 传入 render 函数                       |
|        if (render) {                                      |
|            return match ? render(props) : null;           |
|        }                                                  |
|        return null;                                       |
|  }                                                        |
+-----------------------------------------------------------+
锁窗前月明色, 雕阑外夜气清