手写简版React-router

手写一个简化版本的 React Router,主要实现其核心功能,包括路由配置、路径匹配和导航。

这个简化版本将包括以下组件和函数:

  1. BrowserRouter

  2. Routes 和 Route

  3. Link

  4. useRoutes

  5. useParams

1. 基本框架和组件

1.1. BrowserRouter

BrowserRouter 组件使用 HTML5 History API,并为应用提供路由上下文。

javascript 复制代码
import React, { useState, useEffect, createContext, useContext } from 'react';

const RouterContext = createContext();

function BrowserRouter({ children }) {
  const [location, setLocation] = useState(window.location.pathname);

  useEffect(() => {
    const handlePopState = () => setLocation(window.location.pathname);
    window.addEventListener('popstate', handlePopState);
    return () => window.removeEventListener('popstate', handlePopState);
  }, []);

  const navigate = (to) => {
    window.history.pushState({}, '', to);
    setLocation(to);
  };

  return (
    <RouterContext.Provider value={{ location, navigate }}>
      {children}
    </RouterContext.Provider>
  );
}

1.2. Routes 和 Route

Routes 组件遍历所有子路由,并匹配当前路径,Route 组件定义路径和对应的组件。

javascript 复制代码
function Routes({ children }) {
  const { location } = useContext(RouterContext);
  let element;

  React.Children.forEach(children, (child) => {
    if (!element && React.isValidElement(child) && matchPath(child.props.path, location)) {
      element = child;
    }
  });

  return element;
}

function Route({ path, element }) {
  return element;
}

Link 组件用于导航。

javascript 复制代码
function Link({ to, children }) {
  const { navigate } = useContext(RouterContext);

  const handleClick = (event) => {
    event.preventDefault();
    navigate(to);
  };

  return <a href={to} onClick={handleClick}>{children}</a>;
}

1.4. useRoutes

useRoutes 是一个 hook,用于在函数组件中使用路由。

javascript 复制代码
function useRoutes(routes) {
  const { location } = useContext(RouterContext);

  for (let route of routes) {
    if (matchPath(route.path, location)) {
      return route.element;
    }
  }

  return null;
}

1.5. useParams

useParams 是一个 hook,用于获取路径参数。

javascript 复制代码
function useParams() {
  const { location } = useContext(RouterContext);
  const path = location;
  const match = path.match(/\/([^\/]+)\/?/);
  return match ? { id: match[1] } : {};
}

2. 路径匹配函数

matchPath 用于检查路径是否匹配。

javascript 复制代码
function matchPath(pattern, pathname) {
  const regex = new RegExp(`^${pattern.replace(/:\w+/g, '([^/]+)')}$`);
  return regex.test(pathname);
}

3. 示例应用

基础定义完成,我们在 React 中使用一下这个 router 。

javascript 复制代码
import React from 'react';
import ReactDOM from 'react-dom';

function Home() {
  return <h2>Home</h2>;
}

function About() {
  return <h2>About</h2>;
}

function User() {
  const { id } = useParams();
  return <h2>User ID: {id}</h2>;
}

function App() {
  return (
    <BrowserRouter>
      <nav>
        <Link to="/">Home</Link>
        <Link to="/about">About</Link>
        <Link to="/user/1">User 1</Link>
      </nav>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="/user/:id" element={<User />} />
      </Routes>
    </BrowserRouter>
  );
}

ReactDOM.render(<App />, document.getElementById('root'));

这个简化版的 React Router,主要实现其核心功能,包括路由配置、路径匹配和导航。省略了很多边缘情况和优化,从本例中可以窥见 react-router 框架整体实现最核心的思路。

4. 补充资料

相关推荐
FungLeo4 天前
成为全栈·Next.js 网站前台篇·站点设置如何驱动页头、页脚与 SEO
react·isr·next.js·metadata·成为全栈·站点配置
大连好光景4 天前
ReAct的原理?与CoT的区别是啥?
react·cot
大连好光景4 天前
Agent完整工作过程
react·agent完整工作流程
Alice-YUE6 天前
前端 × AI:从 Cursor 到 Transformer,一份完整认知路径
前端·人工智能·transformer·ai编程·前端开发·cursor
FungLeo7 天前
成为全栈·Next.js 网站前台篇·同源 BFF 代理:API、附件、Cookie 与跨站写入保护
react·csrf·next.js·bff·成为全栈·route handler
Alice-YUE7 天前
React 渲染机制速通:Render 树、Fiber 树与更新调度
前端·react.js·前端框架·react·fiber·前端性能·渲染机制
传奇开心果编程7 天前
【现代声明式UI学与练】第1课 从命令式UI到声明式UI
学习·flutter·ui·swiftui·react·android jetpack
frjc8 天前
前端技术选型:主流方案对比与落地建议
vue·react·angular
Frag0ut12 天前
【深度思考】前端基石的觉醒:探讨 HTML 语言的再进化方向
html5·前端开发·前端架构·大前端·webcomponents·技术趋势·浏览器api
FungLeo12 天前
成为全栈·Next.js 网站前台篇·数据获取与缓存:60 秒再验证背后到底发生了什么
react·isr·next.js·成为全栈·react cache·opennext