最新公告
  • 欢迎您光临网站无忧模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • React router 原理与实现

    正文概述 掘金(咸鱼爱前端)   2021-03-20   456

    React router 中的实现

    react-router的基础——history.js

    history是一个第三方js库,借鉴HTML5 history对象的理念,在其基础上又扩展了一些功能,用来管理历史记录,可以兼容不同的浏览器和不同的环境,根据不同的环境提供了三种不同的API。

    HashHistory:针对老版本的浏览器,主要通过Hash实现。 BrowserHistory:针对较高版本的浏览器,主要通过H5的History实现 MemoryHistory:主要通过内存中的历史记录实现,主要用于Node环境。

    History支持发布/订阅功能,当history发生改变的时候,可以自动触发订阅的函数。 history库可以说是对原生history对象的扩展,使功能更加丰富

    // 内部的抽象实现
    function createHistory(options={}) {
      ...
      return {
        listenBefore, // 内部的hook机制,可以在location发生变化前执行某些行为,AOP的实现
        listen, // location发生改变时触发回调
        transitionTo, // 执行location的改变
        push, // 改变location
        replace,
        go,
        goBack,
        goForward,
        createKey, // 创建location的key,用于唯一标示该location,是随机生成的
        createPath,
        createHref,
        createLocation, // 创建location
      }
    }
    

    重点在于createHistory的实现

    React router 原理与实现 设计思想:

    1. 对History进行了一次封装,使能够识别将url的变化与componet渲染进行匹配
    2. 根据BrowserRouter等不同的API针对H5的history的重构
    3. 结构的构建,同时对history属性进行注册。
    4. 在Router的componentWillMount中注册history的事件回调。
    5. 在Redirect中进行路径的计算,调用 history.push/history.replace 等更新history信息。
    6. Route中根据计算的匹配结果,进行页面首次渲染/页面更新渲染处理。

    为了维护state的状态,可以将其存储在sessionStorage里面:

    // createBrowserHistory/createHashHistory中state的存储
    function saveState(key, state) {
      ...
      window.sessionStorage.setItem(createKey(key), JSON.stringify(state));
    }
    function readState(key) {
      ...
      json = window.sessionStorage.getItem(createKey(key));
      return JSON.parse(json);
    }
    // createMemoryHistory仅仅在内存中,所以操作比较简单
    const storage = createStateStorage(entries); // storage = {entry.key: entry.state}
    
    function saveState(key, state) {
      storage[key] = state
    }
    function readState(key) {
      return storage[key]
    }
    

    react-router-dom 组件结构

    React router 原理与实现

    react-router-dom 提供了BrowserRouter、Route、Link等api,可以通过 dom 操作触发事件控制路由。

    • Link组件,会渲染一个a标签;BrowserRouter和HashRouter组件,前者使用pushState和popState事件构建路由,后者使用hash和 hashchange事件构建路由。
    render() {
        const { replace, to, innerRef, ...props } = this.props; // eslint-disable-line no-unused-vars
    
        invariant(
          this.context.router,
          "You should not use <Link> outside a <Router>"
        );
    
        invariant(to !== undefined, 'You must specify the "to" property');
    
        const { history } = this.context.router;
        const location =
          typeof to === "string"
            ? createLocation(to, null, null, history.location)
            : to;
    
        const href = history.createHref(location);
        return (
          <a {...props} onClick={this.handleClick} href={href} ref={innerRef} />
        );
      }
    
    • react-router-dom在react-router的基础上扩展了可操作dom的api。
    • Swtich 和 Route 都是从react-router中导入了相应的组件并重新导出,没做什么特殊处理。

    Route 实现

     render() {
        const { match } = this.state; // 布尔值,表示 location 是否匹配当前 Route 的 path
        const { children, component, render } = this.props; // Route 提供的三种可选的渲染方式
        const { history, route, staticContext } = this.context.router; // Router 传入的 context
        const location = this.props.location || route.location;
        const props = { match, location, history, staticContext };
    
        if (component) return match ? React.createElement(component, props) : null; // Component 创建
    
        if (render) return match ? render(props) : null; // render 创建
    
        if (typeof children === "function") return children(props); // 回调 children 创建
    
        if (children && !isEmptyChildren(children)) // 普通 children 创建
          return React.Children.only(children);
    
        return null;
      }
    

    switch 实现

      render() {
        const { route } = this.context.router;
        const { children } = this.props;
        const location = this.props.location || route.location;
    
        let match, child;
        React.Children.forEach(children, element => {
          if (match == null && React.isValidElement(element)) {
            const {
              path: pathProp,
              exact,
              strict,
              sensitive,
              from
            } = element.props;
            const path = pathProp || from;
    
            child = element;
            match = matchPath(
              location.pathname,
              { path, exact, strict, sensitive },
              route.match
            );
          }
        });
    
        return match
          ? React.cloneElement(child, { location, computedMatch: match })
          : null;
      }
    

    可直接 npm 安装 react-router-dom,使用其api。

    参考链接:

    react-router的实现原理


    下载网 » React router 原理与实现

    常见问题FAQ

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

    发表评论

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

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

    联系作者

    请选择支付方式

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