最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 关于 react-router- dom 的使用 和 原理

    正文概述 掘金(辉少在写日记呢)   2021-05-16   749

    react-router

    使用

    1、 安装

    npm i react-router-dom
    
    import {
      HashRouter,
      BrowserRouter,
      Route,
      Link,
      Switch,
    } from 'react-router-dom'
    

    用最大的 HashRouter / BrowserRouter 来包裹组件

    <BrowserRouter>
    
        <ul>
            <li>
                 <Link to='/list'>显示列表</Link>
            </li>
            <li>
                 <Link to='/Clock'>显示时间</Link>
            </li>
        </ul>
    
            <div>
            {/* exact 精准匹配 */}
                <Route exact path='/list' component={List}></Route>
                <Route path='/ContextTest' component={ContextTest}></Route>
                <Route exact path='/Clock' component={Clock}></Route>
                <Route path='/reducer' component={Reducer}></Route>
                <Route path='/reftest' component={RefTest}></Route>
                <Route path='/redux' component={Redux}></Route>
                <Route path='/reactredux' component={ReactReduxPage}></Route>
             </div>
    
    
    </BrowserRouter>
    

    当使用switch组件的时候就会从上到下找到合适的组件 叫独占路由

            <Switch>
                <Route exact path='/list' component={List}></Route>
                <Route path='/ContextTest' component={ContextTest}></Route>
                <Route exact path='/Clock' component={Clock}></Route>
                <Route path='/reducer' component={Reducer}></Route>
            </Switch>
    

    如果不写 path 就是匹配任意值

    子路由的渲染优先级是 children > component > render

    Redirect

    要重定向到的位置,其中 pathname 可以是 path-to-regexp 能够理解的任何有效的 URL 路径。

    <Redirect 
        path={'/'} 
        to={{ pathname: '/login', search: '?utm=your+face', state: { referrer: currentLocation }}} 
    />
    

    上例中的 state 对象可以在重定向到的组件中通过 this.props.location.state 进⾏访问。⽽ referrer

    键(不是特殊名称)将通过路径名 /login 指向的登录组件中的 this.props.location.state.referrer 进⾏访问。





    实现 react-router

    暂定 实现一下组件

    import { Route, Link, Switch, BrowserRouter } from '../react-router/index'
    

    我们知道 react 路由有 hashRouter、browerRouter、memoryRouter

    这几个router的作用是传递不同的 historyApi 给 子组件去使用, 将三者api封装成统一的api





    1、关于 BrowserRouter

    传递了 history 的 api给下层

    export class BrowserRouter extends Component {
      constructor(props) {
        super(props)
        this.history = history.createBrowserHistory()
      }
    
      render() {
        return (
          <Router children={this.props.children} history={this.history}></Router>
        )
      }
    }
    





    2、 关于 Router

    这层组件 承接了 不同 路由方式的api的 中间层, 上层传递了history 的统一api 给这层使用

    作用:

    1. 监听路由变化 ,若路由发生改变,则重新渲染当前组件
    2. 通过 createContext 把 history api 传递给 子组件
    3. 把 location 也传给子组件
    4. 传递一个默认path 表示 根路径匹配
    import RouterContext from './context'
    
    export class Router extends Component {
      // 静态方法  传递一个默认path 表示 根路径
      static computeRootMatch(pathname) {
        return { path: '/', url: '/', params: {}, isExact: pathname === '/' }
      }
    
      constructor(props) {
        super(props)
        this.state = {
          location: props.history.location,
        }
        // 提供监听
        this.unlisten = props.history.listen((obj) => {
          this.setState({ location: obj.location })
        })
      }
      componentWillUnmount() {
        this.unlisten() // 执行取消监听
      }
      render() {
        const { children, history } = this.props
        // 提供history跳转 ,和 location 的参数
        return (
          <RouterContext.Provider
            value={{
              history,
              location: this.state.location,
              match: Router.computeRootMatch(this.state.location.pathname),
            }}
          >
            {children}
          </RouterContext.Provider>
        )
      }
    }
    
    

    我们输出 History 看看

    history 包含了以下方法

    比如我们常使用 的 go、push、replace、back

    action: (...)
    back: ƒ ()
    block: ƒ (a)
    createHref: ƒ g(a)
    forward: ƒ ()
    go: ƒ r(a)
    listen: ƒ (a)
    location: Object
    push: ƒ w(a, d)
    replace: ƒ u(a, d)
    get action: ƒ action()
    get location: ƒ location()
    
    hash: ""
    key: "h7fgir2z"
    pathname: "/ContextTest"
    search: "?fuck=true"
    state: null
    





    3、 实现 Link

    其 只提供的 a 标签支持跳转,需屏蔽默认事件

    history api 通过 useContext(RouterContext) 获取

    // 组件 link
    
    export function Link({ children, to, ...restProps }) {
      const { history } = useContext(RouterContext)
      const handleClick = (e) => {
        // 页面跳转
        e.preventDefault()
        history.push(to)
      }
    
      return (
        <a href={''} to={to} onClick={handleClick}>
          {children}
        </a>
      )
    }
    





    4、Route

    1、 作用是显示 匹配路由的 children

    2、 如果有个switch的组件,那computedMatch就会有值

    3、 取值优先级 computedMatch > matchPath(location.pathname, this.props) > context.match 分别就是 取 switch组件给的匹配结果 => 自己的匹配结果 => 根目录结果

    4、children > component > render 除此之外children如果是个函数那么必渲染(上层有switch组件除外)

    5、 通过测试发现 switch 组件会改变 它的children,只会渲染匹配的,没有使用switch组件时,所有 Route 都会渲染,只是渲染结果可能为null。

    
    import matchPath from './matchPath'
    
    export class Route extends Component {
      render() {
        return (
          <RouterContext.Consumer>
            {(context) => {
              const { location } = context
              const { children, component, render, path, computedMatch } = this.props
    
              // 表示匹配的 结果
              const match = computedMatch 
                ? computedMatch
                : path
                ? matchPath(location.pathname, this.props)
                : context.match
    
              // 这里取值的优先顺序是
              
              // computedMatch > matchPath(location.pathname, this.props) > 默认的 match
    
              // console.log('match:', match)
              
              const props = { ...context, match }
    
              // 匹配 children,component,render null
              // 不匹配
    
              return match
                ? children // 1
                  ? typeof children === 'function' // 2
                    ? children(props)
                    : children
                  : component // 3
                  ? React.createElement(component, props)
                  : render // 4
                  ? render()
                  : null
                : typeof children === 'function' // 1
                ? children()
                : null
            }}
          </RouterContext.Consumer>
        )
      }
    }
    





    Switch 组件

    找出 匹配的组件

    export class Switch extends Component {
      render() {
        return (
          <RouterContext.Consumer>
            {(context) => {
              let match;
              let element;
    
              const { location } = context
              
              React.Children.forEach(this.props.children, (child) => {
                if (match == null && React.isValidElement(child)) {
                  element = child
                  match = matchPath(location.pathname, child.props) // 匹配出来的
                }
              })
    
              return match
                ? React.cloneElement(element, { computedMatch: match })
                : null
            }}
          </RouterContext.Consumer>
        )
      }
    }
    





    Redirect 组件

    该组件得和 Route 同级,得有 path 和 to 属性 ,path是为了 给 switch 去和 location.pathname,否则无论如何都会渲染

    export class Redirect extends Component {
      render() {
        return (
          <RouterContext.Consumer>
            {(context) => {
              const { history } = context
              const { to, push = false } = this.props
              return (
                <LifeCycle
                  onMount={() => {
                    push ? history.push(to) : history.replace(to)
                  }}
                ></LifeCycle>
              )
            }}
          </RouterContext.Consumer>
        )
      }
    }
    
    class LifeCycle extends Component {
      componentDidMount() {
        if (this.props.onMount) {
          this.props.onMount.call(this, this)
        }
      }
      render() {
        return null
      }
    }
    





    关于 withRouter

    该方法是一个高阶组件的用法

    需在Route 组件包一层 修改下match的值, 通过 provider

    // 高阶组件
    export const withRouter = (WrappedComponent) => (props) => {
      return (
        <RouterContext.Consumer>
          {(context) => {
            return <WrappedComponent {...props} {...context} />
          }}
        </RouterContext.Consumer>
      )
    }
    
    





    Prompt 实现

    阻碍的原理是 调用 history.block(message)


    起源地下载网 » 关于 react-router- dom 的使用 和 原理

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元