其他分享
首页 > 其他分享> > 分步实现 react-router

分步实现 react-router

作者:互联网

安装 react-router-dom

yarn add react-router-dom

新建页面,可以随便创建,将创建的页面导入、并添加路由在 App.js ,如下:

import { BrowserRouter as Router, Route, Link, Switch } from 'react-router-dom'
<Router>
   <Link to='/'>首页</Link> |
   <Link to='/react-redux'>react-redux</Link> |
   <Link to='/redux'>redux</Link> |
   <Link to='/hook'>Hook</Link>
   <Switch>
      <Route exact path="/" component={HomePage} />
      <Route path="/react-redux" component={ReactReduxPage} />
      <Route path="/redux" component={ReduxPage} />
      <Route path="/hook" component={HooksPage} />
      {/* <Route  component={404} /> */}
   </Switch>
</Router>

明确 react-router-dom Api 的作用

   BrowserRouter : Router的一种,通过使用HTML5提供的history API(pushState,replaceState,propstate)机制来维持页面UI同RUL的统一。
   HashRouter : 使⽤用URL的hash部分(即window.location.hash)来保持UI同RUL的统一。
   MemoryRouter : 把URL的历史记录保存在内存中的 <Router>(不读取、不写⼊地址栏)。在测试和⾮浏览器器环境中很有⽤用,如React Native。
   Router : 路由器,作为中间件传递数据。
   Link : a 链接,跳转页面。
   Switch : 匹配路由(独占路由)。
   Route : 路由,渲染页面(children、component、render)。
   Redirect : 重定向到的URL。
   Prompt : 跳出当前路由时,提示。

实现,BrowserRouter.js

其实BrowserRouter作为区分项目中路由的选择性 API,其作用肯定就是向下传递路径,也就是对象 history。然后子组件监听,并选择其与之相对应的匹配方式。

import React from 'react'
import Router from './Router';
import { createBrowserHistory } from 'history';
export default class BrowserRouter extends React.Component {
    constructor(props) {
        super(props);
        this.history = createBrowserHistory()
    }
    componentDidMount() { }
    render() {
        return <Router history={this.history} children={this.props.children} />
    }
}

实现,Router.js

import React from 'react';
const RouterContext = React.createContext()
export default RouterContext
<RouterContext.Provider
    value={{
       history: this.props.history,
       location: this.state.location,
       match: Router.computeRootMatch(this.state.location.pathname),
    }
    }
>
    { this.props.children}
</RouterContext.Provider >
  props.history.listen((location) => {
      this.setState({
            location
      })
   })
static computeRootMatch(pathname) {
     return { path: "/", url: "/", params: {}, isExact: pathname === "/" };
  }

实现Link.js

const handleClick = (event) => {
   event.preventDefault();
   context.history.push(to)
}
...
<a href={to} onClick={handleClick} {...restProps}>{children}</a>

实现Route.js

<Route exact path="/" children={ChildFn}  />
<Route exact path="/"  component={HomePage} />
<Route exact path="/" render={() => <div>Home</div>} />
const { location } = context
const { path, children, component, render, computedMatch } = this.props
const match = computedMatch
   ? computedMatch : path
         ? matchPath(location.pathname, this.props) : context.match;
<RouterContext.Provider value={props}>
   {props.match
      ? children
      ? typeof children === "function"
         ? __DEV__
            ? evalChildrenDev(children, props, this.props.path)
            : children(props)
         : children
      : component
      ? React.createElement(component, props)
      : render
      ? render(props)
      : null
      : typeof children === "function"
      ? __DEV__
      ? evalChildrenDev(children, props, this.props.path)
      : children(props)
      : null}
</RouterContext.Provider>

可见,匹配的顺序是children>component>render

实现Switch.js

<Route path="/about" component={About} />
<Route path="/:user" component={User} />
<Route component={404} />

如果URL是/about时,<Switch> 将开始寻找匹配的<Route> 。此时找到第一个 将会被正确匹配,并渲染,然后,后面的便不再渲染,这就是独占。其原理就是:利用React原生APIReact.Children.forEach递归,并定位当前的child

React.Children.forEach(this.props.children, (child) => {
   if (match == null) {
         element = child;
         match = child.props.path ? matchPath(location.pathname, child.props) : context.match
   }
});

最后,就是整理思路。

本文源码归处☞源码

标签:react,分步,props,组件,router,history,children,Router,location
来源: https://blog.csdn.net/xunyicao_e/article/details/114519837