手写简版React-router
手写一个简化版本的 React Router,主要实现其核心功能,包括路由配置、路径匹配和导航。
这个简化版本将包括以下组件和函数:
1. BrowserRouter
2. Routes 和 Route
3. Link
4. useRoutes
5. useParams
1. 基本框架和组件
1.1. BrowserRouter
BrowserRouter 组件使用 HTML5 History API,并为应用提供路由上下文。
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 组件定义路径和对应的组件。
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;
}
1.3. Link
Link 组件用于导航。
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,用于在函数组件中使用路由。
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,用于获取路径参数。
function useParams() {const { location } = useContext(RouterContext);const path = location;const match = path.match(/\/([^\/]+)\/?/);return match ? { id: match[1] } : {};
}
2. 路径匹配函数
matchPath 用于检查路径是否匹配。
function matchPath(pattern, pathname) {const regex = new RegExp(`^${pattern.replace(/:\w+/g, '([^/]+)')}$`);return regex.test(pathname);
}
3. 示例应用
基础定义完成,我们在 React 中使用一下这个 router 。
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. 补充资料
-
官方文档:React Router Official Documentation
-
react-router-dom 多类型历史:https://github.com/remix-run/react-router/blob/acc2b94088835d1247bdf3a3f883f74cc3570a0/packages/react-router-dom/index.tsx#L262
-
wouter: https://github.com/molefrog/wouter
-
@tanstack/router:TanStack Router
-
浏览器历史记录协议:History API - Web APIs | MDN