react-router简易实现

react-router

利用context hashchange 实现router

大致思路如下

  • 利用context保证唯一路由信息,以及传递路由信息
  • 监听hashchange 修改当前路由信息

ps 以下代码都是基于hooks,而且只实现了HashRouter,如果要实现BrowserRouter就要监听popstate事件

//HashRouter.js
import React, { useState, useEffect } from 'react';
import Context from "./context";
const HashRouter = (props) => {
const [location,setLocation]=useState({
    pathname: window.location.hash.slice(1) || "/", // 获取浏览器地址栏中的hash值,如果不存在则默认为"/"
    query: undefined
})
useEffect(()=>{
    window.addEventListener("hashchange", () => { // 监听浏览器地址栏hash值变化
        setLocation(
            {
                ...location,
                pathname: window.location.hash.slice(1) // 更新pathname
            }
        )
    });
},[])
const currentRoute = {
    location: location, 
    history: { // 新增一个history对象用于实现当前路由的切换
        push: (to) => {
            if (typeof to === "object") { // 如果to是一个对象
                let { pathname, query } = to; // 取出pathname和query
                window.location.hash = pathname; // 更新浏览器hash值,触发浏览器hashchange事件
                location.query = query; // 更新query
            } else { // 修改浏览器地址栏的hash值
                window.location.hash = to; // 更新浏览器hash值
            }
        }
    }
}
return (
    <Context.Provider value={currentRoute}>
        {props.children}
    </Context.Provider>
);
};
export default HashRouter;

//Route.js
import React, {useContext} from "react";
import Context from "./context";
const Route = (props) => {
const context=useContext(Context)
const currentRoutePath = context.location.pathname; // 从上下文中获取到当前路由的路径
const {path, component:Component} = props; // 获取给Route组件传递的props属性
const props2 = {
    ...context
}
if (currentRoutePath === path) {
    return (
        <Component {...props2}></Component>
    );
}
return null
};
export default Route;

完整代码地址:https://github.com/dz333333/toy–router
参考:https://segmentfault.com/a/1190000022250917

从输入URL到页面展示 导航流程

导航流程

  • 用户输入url并回车
  • 浏览器进程检查url,组装协议,构成完整的url
  • 浏览器进程通过进程间通信(IPC)把url请求发给网络进程
  • 网络进程接收到url请求后检查本地缓存是否缓存了该请求资源,如果有则将该资源返回给浏览器进程
  • 如果没有,网络进程向web服务器发起http请求(网络请求)请求流程如下:
    • 进行DNS解析,获取服务器ip地址,端口
    • 利用ip地址和服务器建立tcp连接
    • 构建请求头信息
    • 发送请求头信息
    • 服务器响应后,网络进程接收响应头和响应信息,并解析响应内容
  • 网络进程解析响应流程
    • 检查状态码,如果是301/302,则需要重定向,从location字段中读取地址,重新进行第4步,如果是200,则继续处理请求
    • 200响应处理:检查响应类型Content-Type,如果是字节流类型,则将该请求提交给下载管理器,该导航流程结束,不再进行后续的渲染,如果是html则通知浏览器进程准备渲染进程准备进行渲染
  • 准备渲染进程
    • 浏览器进程检查当前url是否和之前打开的渲染进程根域名是否相同,如果相同,则复用之前的进程,如果不同,则开启新的渲染进程
  • 传输数据、更新状态
    • 渲染进程准备好后,浏览器向渲染进程发起 "提交文档"的消息,渲染进程接收到消息后和网络进程建立数据传输的"管道"
    • 渲染进程接受完数据后,向浏览器发送"确认提交"
    • 浏览器进程接收到确认消息后更新浏览器界面状态:包括了安全状态、地址栏的URL、前进后退的历史状态,并更新Web页面。

参考:李兵老师的浏览器工作原理与实践