当前位置: 移动技术网 > IT编程>开发语言>JavaScript > 浅谈react-router@4.0 使用方法和源码分析

浅谈react-router@4.0 使用方法和源码分析

2019年07月19日  | 移动技术网IT编程  | 我要评论

react-router-dom@4.3.0 || react-router@4.4.1

react-router 使用方法

配置 router.js

import react, { component } from 'react';
import { switch, route } from 'react-router-dom';

const router = [{
  path: '/',
  exact: true,
  component:importpath({
   loader: () => import(/* webpackchunkname:"home" */ "pages/home/index.js"),
  }),
 },]
const routers = () => (
 <main>
  <switch>
   {
    router.map(({component,path,exact},index)=>{
     return <route exact={exact} path={path} component={component} key={path} />
    })
   }
  </switch>
 </main>
);

export default routers;

入口 index.js

import {hashrouter} from 'react-router-dom';
import react from 'react';
import reactdom from 'react-dom';
import routers from './router';

reactdom.render (
   <hashrouter>
    <routers />
   </hashrouter>,
 document.getelementbyid ('app')
);

home.js

import { withrouter } from "react-router-dom";

@withrouter
class home extends react.component<propstype, statetype> {
 constructor(props: propstype) {
  super(props);
  this.state = {};
 }
 gopath=()=>{
   this.props.history.push('/home')
 }
 render() {
  return (
   <div onclick={this.gopath}>home</div>
  );
 }
export default home;

react-router 源码解析

下面代码中会移除部分的类型检查和提醒代码,突出重点代码

第一步 switch react-router

function _possibleconstructorreturn(self, call) {
 if (!self) {
  throw new referenceerror("this hasn't been initialised - super() hasn't been called");
 }
 if(call&&(typeof call === "object" || typeof call === "function") ){
  return call
 }else {
  return self
 }
}
var switch = function (_react$component) {
 function switch() {
  //使用传递进来的组件覆盖本身
  return _possibleconstructorreturn(this, _react$component.apply(this, arguments)); 
 }
 switch.prototype.render = function render() {
  var route = this.context.router.route;
  var children = this.props.children;
  var location = this.props.location || route.location;
  var match = void 0,child = void 0;
  
  //检查element是否是react组件,初始match为null,
  react.children.foreach(children, function (element) {
   //如果match符合,foreach不会进入该if
   if (match == null && react.isvalidelement(element)) { 
    var _element$props = element.props,
      pathprop = _element$props.path,
      exact = _element$props.exact,
      strict = _element$props.strict,
      sensitive = _element$props.sensitive,
      from = _element$props.from;
    var path = pathprop || from;
    child = element; 
    //检查当前配置是否符合,
    match = matchpath(location.pathname, { path: path, exact: exact, strict: strict, sensitive: sensitive }, route.match); 
   }
  });
  //如果有匹配元素,则返回克隆child
  return match ? react.cloneelement(child, { location: location, computedmatch: match }) : null;
 };

 return switch;
}(react.component);

总结:switch根据location.pathname,path,exact,strict,sensitive获取元素并返回element

第二步 route react-router

var route = function (_react$component) {
 function route() {
  var _temp, _this, _ret;
  //获取参数
  for (var _len = arguments.length, args = array(_len), _key = 0; _key < _len; _key++) {
   args[_key] = arguments[_key];
  }
  //修改this
  return _ret = (
   _temp = (_this = _possibleconstructorreturn(this, _react$component.call.apply(_react$component, [this].concat(args))), _this), 
   //检查当前元素是否符合match
   _this.state = {match: _this.computematch(_this.props,_this.context.router)},_temp),
    //这里是真正return
    _possibleconstructorreturn(_this, _ret); 
 }
 // 设置content
 route.prototype.getchildcontext = function getchildcontext() {
  return {
   router: _extends({}, this.context.router, {
    route: {
     location: this.props.location || this.context.router.route.location,
     match: this.state.match
    }
   })
  };
 };
 // 根据参数检查当前元素是否符合匹配规则
 route.prototype.computematch = function computematch(_ref, router) {
  var computedmatch = _ref.computedmatch,
    location = _ref.location,
    path = _ref.path,
    strict = _ref.strict,
    exact = _ref.exact,
    sensitive = _ref.sensitive;

  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);
 };
 // 设置match
 route.prototype.componentwillreceiveprops = function componentwillreceiveprops(nextprops, nextcontext) {
  this.setstate({
   match: this.computematch(nextprops, nextcontext.router)
  });
 };

 route.prototype.render = function render() {
  var match = this.state.match;
  var _props = this.props,
    children = _props.children,
    component = _props.component,
    render = _props.render;
  var _context$router = this.context.router,
    history = _context$router.history,
    route = _context$router.route,
    staticcontext = _context$router.staticcontext;

  var location = this.props.location || route.location;
  var props = { match: match, location: location, history: history, staticcontext: staticcontext };
  //检查route 是否有component组
  if (component) return match ? react.createelement(component, props) : null; 
  // 检查是否包含render 组件
  if (render) return match ? render(props) : null;
  // withrouter 使用的方式
  if (typeof children === "function") return children(props);

  if (children && !isemptychildren(children)) return react.children.only(children);

  return null;
 };

 return route;
}(react.component);

总结:route 渲染的方式: component render children,代码示例用的是component,route 是检查当前组件是否符合路由匹配规则并执行创建过程

第三步 hashrouter react-router-dom

import router from './router'
import {createhistory} from 'history'
var hashrouter = function (_react$component) {
 function hashrouter() {
  var _temp, _this, _ret;
  //参数转换为数组
  for (var _len = arguments.length, args = array(_len), _key = 0; _key < _len; _key++) { 
   args[_key] = arguments[_key];
  }
  return _ret = (
   _temp = (_this = _possibleconstructorreturn(this, _react$component.call.apply(_react$component, [this].concat(args))), _this),
    _this.history = createhistory(_this.props), _temp), //创建history
    _possibleconstructorreturn(_this, _ret); //真正返回的东西 返回this
 }
 hashrouter.prototype.render = function render() {
  // 返回一个router,并且把history,children传递给router
  return react.createelement(router, { history: this.history, children: this.props.children });
 };
 return hashrouter;
}(react.component);

总结 通过 history库里面 createhistory 创建路由系统

第四部 router react-router

var router = function (_react$component) {
 function router() {
  var _temp, _this, _ret;
  //获取参数,和其他组件一样
  for (var _len = arguments.length, args = array(_len), _key = 0; _key < _len; _key++) {
   args[_key] = arguments[_key];
  }
  return _ret = (_temp = (_this = _possibleconstructorreturn(this, _react$component.call.apply(_react$component, [this].concat(args))), _this), _this.state = {
   match: _this.computematch(_this.props.history.location.pathname) //返回路由对象
  }, _temp), _possibleconstructorreturn(_this, _ret); //返回this
 }
 // 返回context
 router.prototype.getchildcontext = function getchildcontext() {
  return {
   router: _extends({}, this.context.router, {
    history: this.props.history,
    route: {
     location: this.props.history.location,
     match: this.state.match
    }
   })
  };
 };
  
 router.prototype.computematch = function computematch(pathname) {
  return {
   path: "/",
   url: "/",
   params: {},
   isexact: pathname === "/"
  };
 };

 router.prototype.componentwillmount = function componentwillmount() {
  var _this2 = this;

  var _props = this.props,
    children = _props.children,
    history = _props.history;

  // 启动监听 当hash 改变是做一次检查,并返回unlisten 取消事件
  this.unlisten = history.listen(function () {
   _this2.setstate({
    match: _this2.computematch(history.location.pathname)
   });
  });
 };
 //销毁前取消监听
 router.prototype.componentwillunmount = function componentwillunmount() {
  this.unlisten();
 };
 // children是hashrouter 传递进来的
 router.prototype.render = function render() {
  var children = this.props.children;
  return children ? react.children.only(children) : null;
 };

 return router;
}(react.component);

总结 history是一个javascript库,可让您在javascript运行的任何地方轻松管理会话历史记录。history抽象出各种环境中的差异,并提供最小的api,使您可以管理历史堆栈,导航,确认导航以及在会话之间保持状态。

第五部 withrouter <react-router>

var withrouter = function withrouter(component) {
 var c = function c(props) {
  //获取props
  var wrappedcomponentref = props.wrappedcomponentref,
    remainingprops = _objectwithoutproperties(props, ["wrappedcomponentref"]);
  // route 组件 children方式
  return react.createelement(route, {
   children: function children(routecomponentprops) {
    // 这里使用的是route 组件 children(props)
    //routecomponentprops 实际等于 { match: match, location: location, history: history, staticcontext: staticcontext };
    return react.createelement(component, _extends({}, remainingprops, routecomponentprops, {
     ref: wrappedcomponentref
    }));
   }
  });
 };

 c.displayname = "withrouter(" + (component.displayname || component.name) + ")";
 c.wrappedcomponent = component;
 // 该类似于object.assign(c,component),得到的结果是c
 return hoiststatics(c, component);
};

到这里真个流程基本结束了,这只是react-router的一种使用方式的解析,本文的目的是理解react-router的运行机制,如果有什么错误还望指出,谢谢

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网