欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2023-12-20 22:03:10
react-router-dom@4.3.0 || react-router@4.4.1 react-router 使用方法 配置 router.js i...

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的运行机制,如果有什么错误还望指出,谢谢

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

上一篇:

下一篇: