react路由

91 阅读1分钟

router

constructor(props) {
  super(props)

  this.state = {
    // history会计算出当前的path等信息,保存在location属性上,作为 <Router /> 的props
    location: props.history.location
  };


  componentDidMount() {
    this.unlisten = props.history.listen(location => {
      this.setState({ location }) // 触发应用的更新
    })
  }

  render() {
    return (
      // 给 route 用
      <RouterContext.Provider
        value={{
          history: this.props.history,
          location: this.state.location,
          match: Router.computeRootMatch(this.state.location.pathname),
        }}
      >
        {this.props.children || null}
      </RouterContext.Provider>
    )
  }
}

route

class Route extends React.Component {
  render() {
    return (
      <RouterContext.Consumer>
        {
          context => {
            const location = context.location; // 路由相关
            const match = this.props.path      // 是否匹配当前url
              ? matchPath(location.pathname, this.props)
              : context.match;
			
            const props = { ...context, location, match }
			
            let { children, component, render } = this.props

            // children不能有多个
            if (Array.isArray(children) && children.length === 0) children = null;
            
            return (
              // 我理解是给 withRouter 等这种高阶组件获取history的
              <RouterContext.Provider value={props}>
                // 如果 path 匹配上了, 渲染children
                {props.match
                  ? children
                    ? typeof children === "function"
                      ? children(props)
                      : children
                    // 然后是 component
                    : component
                      ? React.createElement(component, props)
                      // render
                      : render
                        ? render(props)
                        : null
                  : typeof children === "function"
                    ? children(props)
                    : null}
              </RouterContext.Provider>
              // 1. 渲染的优先级是  children > component > render;
              // 2. 如果没有匹配上path, children如果是function,那么也会渲染出来;
            )
        }}
      </RouterContext.Consumer>
    );
  }
}