注册

简易版 React-Router实现

上一篇简单的介绍了react-router 的使用方法和基本的API,对于react-router几个重要的API做了源码解读。这篇就实现一个简易版的 react-router

设计思路

afaa7353bec8848e36d4ba2bbf7ecf6c.png

由上图可知,核心内容就是如何监听到URL的改变?图中说到三种方式,其实也就两种pushstate 和 浏览器的前进和回退。刷新页面还是处于当前的URL,不涉及URL的改变。上一篇文章中也讲到 前端路由的原理有两点

  1. URL改变 页面不刷新。
  2. 监听到URL的改变。

所以在设计 react-router 的时候需要考虑 pushstate 和 浏览器的前进和回退这两种方式的URL改变。

Router

功能:负责监听页面对象发生了改变,并开始重新渲染页面 **

  1. 先定义一个上下文,方便把history数据传入所有的子组件
const RouteContext = React.createContext({})
  1. 定义 Router 组件,主要内容监听URL变化
const globalHistory = window.history // history 使用window 全局的history
class Router extends React.Component {
constructor(props) {
super(props)
this.state = { // 把location 设置为state 每次URL的改变,能够更新页面
location: window.location
}
// 第一种跳转方式:浏览器的前进后退,触发popstate 事件
window.addEventListener("popstate", () => {
this.setState({
location: window.location
})
})
}
// 第二种跳转方式:pushstate
// 向子组件提供push 方法更新路由,跳转页面
push = (route) => {
globalHistory.pushState({}, "", route)
this.setState({
location: window.location
})
}
// 定义上下文,把通用内容传入子组件
render() {
const { children } = this.props
const { location } = this.state
return (
<RouteContext.Provider value={{
history: globalHistory,
location,
push: this.push,
}}>
{
React.cloneElement(children, {
history: globalHistory,
location,
push: this.push,
})
}
</RouteContext.Provider>
)
}
}

export default Router

Route

功能:页面开始渲染后,根据具体的页面location信息展示具体路由地址对应的内容 **

import React, { useContext } from 'react'
const Route = (props) => {
// 在上下文中获取到相关信息
const context = useContext(RouteContext)
// 计算 location 匹配到的 path
const computedPath = (path, exact) => {
...TODO
// 这里内容和源码一样,其核心使用了path-to-regexp 库,能够计算出URL中的参数
}
// eslint-disable-next-line no-unused-vars
const { render, children, component, path, exact = false, ...rest } = props
const match = computedPath(path, exact)
const params = { ...context, match, location: context.location }
// 渲染 也就是源码中的三目运算。把相关的属性传入子组件
if (match) {
if (children) {
if (typeof children === 'function') {
return children(params)
}
return React.cloneElement(children, params)
} else if (component) {
return component(params)
} else if (render) {
return render(params)
}
}
return null
}

export default Route

这样一个简单的React-Router 就实现了,能够实现页面的跳转。

完整代码:https://github.com/LiuSandy/web

原文链接:https://zhuanlan.zhihu.com/p/366482879


0 个评论

要回复文章请先登录注册