react-router原理探索

react-router原理探索
history

history是浏览器提供的api,window.history指向History对象,表示当前的浏览历史。提供的api如下:

history.pushState(state,title,url)// 往路由加入要给堆栈,并且跳转,不刷新页面
history.replaceState(state,title,url)// 替换当前路由,不刷新页面。
history.go()// 后退或前进几次
history.forward()// 前进
history.back()// 返回

history不怕刷新,不怕前进和后退。怕刷新。因为刷新会实实在在请求后端服务器,如果服务器没有对应的资源返回会得到404。

hash

hash是为前端spa单页面准备的,地址栏后面的#符号,www.aaa.com/aaa/#/hello,#/hello 就是hash值。他的改变不会重新加载页面,对后端没有影响。提供了hashChange监听函数,

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>history</title>
</head>
<body>
    <div>
        <a href="#/111">111</a>
        <a href="#/222">222</a>
        <a href="#/333">333</a>
    </div>
    <script>
        window.addEventListener('hashchange',(e)=>{
            console.log('e',e);
            console.log('oldURL', e.oldURL);
        console.log('newRUL', e.newURL);
        })
    </script>
</body>
</html>
history和hash对比

history更符合我们常见的路由,但他需要服务器的支持,也便于seo优化。怕刷新

hash路由后面多了#号,会丑一点,他的路由控制完全交给前端,不需要后端介入。对于前端spa单页面应用。不便于seo优化。

react-router-demo
案例代码

用到了两种路由,切换即可,Link、Route

import React from "react";
import {
  HashRouter as Router,
  Route,
  Link
} from "../router-demo/react-router-dom";
import About from '../pages/About'
import Home from '../pages/Home'
import Users from '../pages/Users'
const RouterProvider=()=>{
    return  <Router>
    <div>
      <nav>
        <ul>
          <li>
            <Link to="/">Home</Link>
          </li>
          <li>
            <Link to="/about">About</Link>
          </li>
          <li>
            <Link to="/users">Users</Link>
          </li>
        </ul>
      </nav>


        <Route path="/about">
          <About />
        </Route>
        <Route path="/users">
          <Users />
        </Route>
        <Route path="/" exact>
          <Home />
        </Route>
    </div>
  </Router>
}
export default RouterProvider;
react-router-dom----BrowserRouter和HashRouter

这两个都是基于history这个库去创建的基于window.history和hash的路由,代码相对简单

import React from 'react';
import {createHashHistory} from 'history';
import { Router } from '../react-router';

 export default class BrowserRouter extends React.Component{
     // 创建hash路由实例,包含push等操作。
     history=createHashHistory();
     render(){
         // 返回router,利用react的context做深层组件的值传递。
        return  <Router history={this.history} children={this.props.children} />;
    }
}
react-router—Router
import React from 'react';
// 这个RouterContext就是创建routerContet而已。
import RouterContext from './RouterContext';
class Router extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            location: props?.history.location
          };
            // 重点是在这里的,当我们使用的history的库,他为我们封装好的监听路由改变的方法,监听到改变,把当前的location接收到,通过context传递。
          props.history.listen(location=>{
              this.setState({
                  location
              })
          })
    }
    static computeRootMatch(pathname) {
        return {
            path: "/",
            url: "/",
            params: {},
            isExact: pathname === "/"
        };
    }
    render() {
        // 使用react的context多组件共享location,
        return <RouterContext.Provider
        children = {
            this.props.children || null
        }
        value = {
            {
                history: this.props.history,
            // 这里传递。
                location:this.state.location,
                match:Router.computeRootMatch(this.state.location?.pathname),

            }
        }
        >
            
        </RouterContext.Provider>
    }
}
export default Router;
react-router—Route
import React from 'react';
import RouterContext from './RouterContext';
import matchPath from './matchPath';
class Route extends React.Component{
    render(){
        return <RouterContext.Consumer>
            {context=>{
             // 这要靠match,去控制是否显示对应的路由
                const match=matchPath(context.location,this.props);
                return match?this.props.children:null;
            }}
        </RouterContext.Consumer>
    }
}
export default Route;
react-router—matchPath
const  matchPath=(pathname,options={})=>{
if(pathname.pathname===options.path) return true;
return false;
}
export default matchPath;

这一整个逻辑下来,简易版本的react-router就已经形成了。能够实现路由的跳转相关操作。

写到最后

总结,react-router不算复杂,他的思路是根据浏览器自身的history和hash路由,监听路由的变化,利用context传递当前location和Route进行比较,控制渲染。

简易版本实现的地址:https://github.com/lqy0101/fe-code-analysis/tree/main/example/react/react-router-demo

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值