幽灵路由 - 实现无副作用的单元式路由系统

91 阅读2分钟

GhostRouter

项目地址 igit.58corp.com/wuxianfe/bu…

使用场景

在我们开发一个独立的组件,或者npm包时,希望在这个环境中使用路由系统,此路由系统需要满足以下条件

  • 在宿主项目中使用该组件或npm包时不需要进行任何额外的路由配置;
  • 不能够对宿主项目产生路由副作用;

功能

1.路由切换功能

  • 能够进行 push、back,replace等的常规路由操作动作
  • 能够实现Link组件,方便开箱即用

2.路由匹配功能

  • 能够实现路由的匹配
  • 能够解析路由中的参数
  • 能够标准化的输入/输出路由地址

3.对宿主路由无副作用

  • 需要对宿主路由无副作用,能够独立运行

实现方式

1.使用hash路由

why? 因为hash路由更可控,变更时不会造成页面刷新,无论宿主使用hash或者hsitory,都不会对宿主有影响。

2.通过特定的标识符(本项目中使用/-/)分隔宿主路由与幽灵路由的path部分

Eg: Https://www.58.com/admin/#/user/-/ghost/pageA 此时 幽灵路由部分为 /ghost/pageA

3.通过ReactHooks驱动
4.通过context进行数据分发
5.通过绑定hashChange事件实现路由变化的实时监听

流程

整体流程

ghostrouter.png

数据处理流程

ghostrouterhandler.png

组件及方法

hooks

useGhostHistory

核心Hook,幽灵路由的中枢

  • 提供格式化后的路由信息
  • 暴露路由的可操作方法 pushreplaceback

useHashChangeEffect

  • 提供全局的 hashChange 的绑定以及触发副作用

usePathToUrl

  • 提供路由格式化的方法,该方法会在当前路由改变时重新计算路由,使得输出的使用路由保持最新状态

组件

GhostSwitch

  • 提供GhostHistory实例对GhostRouter的下发动作

GhostRouter

  • 解析路由规则
  • 进行路由匹配性校验
  • 提取路由规则中的参数

Link

  • 提供组件式的路由调用方式
  • 内部以 a 标签为实现基础

使用方式

import {
  GhostSwitch,
  GhostRouter,
  useGhostHistory,
} from "@w/tianqi-ghost-router";
import type { ConnectProps } from "@w/tianqi-ghost-router";

const PageA = () => <>PageA</>;

// 触发push方法
const PageB = ({ ghostHistory }: ConnectProps<any>) => {
  return (
    <div>
      <button onClick={() => ghostHistory.push("/page-c/1")}>jump</button>
    </div>
  );
};

// 取路由参数
const PageC = ({ ghostHistory }: ConnectProps<{ id: string }>) => {
  const { id } = ghostHistory.match;
  return <div>PageC: {id}</div>;
};

const PageContainer = () => {
  const [ghostHistory] = useGhostHistory();
  return (
    <GhostSwitch ghostHistory={ghostHistory}>
      <GhostRouter path="/page-a" extra components={<PageA />} />
      <GhostRouter path="/page-b" components={<PageB />} />
      <GhostRouter path="/page-c/:id" components={<PageBC />} />
    </GhostSwitch>
  );
};