浅谈react-router@4.0 使用方法和源码分析
程序员文章站
2023-12-18 17:26:34
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的运行机制,如果有什么错误还望指出,谢谢
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
推荐阅读
-
浅谈react-router@4.0 使用方法和源码分析
-
JDK源码分析之String、StringBuilder和StringBuffer
-
浅谈MySQL和Lucene索引的对比分析
-
Android透明化和沉浸式状态栏实践及源码分析
-
JDK源码分析之String、StringBuilder和StringBuffer
-
Android透明化和沉浸式状态栏实践及源码分析
-
PHP中array_keys和array_unique函数源码的分析
-
浅谈sql语句中GROUP BY 和 HAVING的使用方法
-
深入理解react-router@4.0 使用和源码解析
-
vuex 源码分析(一) 使用方法和代码结构