路由和SPA

  • 传统网页,浏览器根据 url 向服务器请求对应的文件(html/css/js)
  • SPA(single-page application) 服务器只专注于提供数据,JS/CSS/HTML打包为一个超集大的文件一次性丢给浏览器, JS劫持浏览器路由,生成虚拟路由来动态渲染页面DOM元素

React路由框架

  • 综合性路由框架: react-router
  • 浏览器路由框架: react-keeper
  • react-native路由框架:react-navigation

react-router

  • react-router-dom 用于浏览器,处理Web App的路由
    • 会自动安装 react-router 核心框架
    • 组件可以渲染出标签
    • 组件利用HTML5 History API实现路由切换
    • 组件利用原生JS中的window.location.hash来实现路由切换
  • react-router-native 用于React Native, 处理手机app的路由
  • react-router-redux 提供了路由中间件,处理redux的集成
  • react-router-config 用来静态配置路由

安装react-router-dom

  1. yarn add react-router-dom
  2. yarn add --dev @types/react-router-dom

BrowserRouter 和 HashRouter的区别:

  • BrowserRouter的url不带#, 请求不同的页面都是不同的url, 服务器需要对每个url都做响应配置
  • HashRouter带#, #后的内容不会传给服务器,服务器始终响应一个url

react-router已经升级到了v6 查看详细变化
使用react-router(这里是react-router最新版本6的用法)

  1. // react-router 6 写法
  2. import styles from './App.module.css'
  3. import { BrowserRouter, Routes, Route } from 'react-router-dom'
  4. import { HomePage, SignInPage, RegisterPage, DetailPage } from './pages'
  5. function App() {
  6. return (
  7. <div className={styles.App}>
  8. <BrowserRouter>
  9. <Routes>
  10. <Route path="/" element={<HomePage />} />
  11. <Route path="/signIn" element={<SignInPage />} />
  12. <Route path="/register" element={<RegisterPage />} />
  13. <Route path="/detail/:id" element={<DetailPage />} />
  14. <Route path="*" element={<div>404 not found</div>} />
  15. </Routes>
  16. </BrowserRouter>
  17. </div>
  18. )
  19. }
  20. export default App

与 react-router 5 对比

  • 5 需要 exact 精确匹配,6已经不需要了
  • 6 将 Switch 换成了 Routes
  • 6 中render和component都改用element
  • 6 中 404 页面 path="*" ```tsx // react-router 5 写法

import React from ‘react’; import styles from “./App.module.css”; import { BrowserRouter, Route, Switch } from “react-router-dom”; import { HomePage, SignInPage, RegisterPage, DetailPage } from “./pages”;

function App() { return (

404 not found 页面去火星了 !

} />
); }

export default App;

  1. <a name="s2orp"></a>
  2. #### 如何在URL中添加参数?
  3. - 第一种使用query string: http://localhost/path?name1=value1&name2=value2
  4. - 第二种使用Restful ID: http://localhost/path/:userid
  5. 在组件中获取url 参数
  6. ```tsx
  7. import { useParams } from 'react-router'
  8. export const DetailPage = () => {
  9. const { touristRouteId } = useParams()
  10. return <h1>产品详情, ID: {touristRouteId}</h1>
  11. }

在 react-router 5 中是可以通过 props 获取参数的,6 已经不可以了

  1. import React from "react";
  2. import { RouteComponentProps } from "react-router-dom";
  3. interface MatchParams {
  4. touristRouteId: string;
  5. }
  6. export const DetailPage: React.FC<RouteComponentProps<MatchParams>> = (
  7. props
  8. ) => {
  9. // console.log(props.history);
  10. // console.log(props.location);
  11. // console.log(props.match);
  12. return <h1>路游路线详情页面, 路线ID: {props.match.params.touristRouteId}</h1>;
  13. };

useHistory VS useNavigate

在 react-router 5 中,通过操作 history 实现跳转

  1. // This is a React Router v5 app
  2. import { useHistory } from "react-router-dom";
  3. function App() {
  4. let history = useHistory();
  5. function handleClick() {
  6. history.push("/home");
  7. }
  8. return (
  9. <div>
  10. <button onClick={handleClick}>go home</button>
  11. </div>
  12. );
  13. }

而在 react-router 6 中使用新的API navigate实现跳转

  1. // This is a React Router v6 app
  2. import { useNavigate } from "react-router-dom";
  3. function App() {
  4. let navigate = useNavigate();
  5. function handleClick() {
  6. navigate("/home");
  7. }
  8. return (
  9. <div>
  10. <button onClick={handleClick}>go home</button>
  11. </div>
  12. );
  13. }

navigate(to, { replace: true }) 替代 history.replace(to)

Redirect VS Navigate

react-router 5 中使用 Redirect 实现路由重定向

  1. <Redirect to="about" /> // 默认是replace
  2. <Redirect to="home" push />

react-router 6 中使用 Navigate 实现路由重定向

  1. <Navigate to="about" replace />
  2. <Navigate to="home" /> // 默认是push

Link

Link也可以实现跳转

  1. <Link to="/invoices">Invoices</Link>
  2. <Link to="/expenses">Expenses</Link>

原理

  1. interface LinkProps {
  2. to: string;
  3. }
  4. const Link: React.FC<LinkProps> = ({children, to}) => {
  5. const history = useHistory()
  6. return (
  7. <a href={to} onClick={()=>{history.push(to)}}>
  8. {children}
  9. </a>
  10. )
  11. }

React-router 6 文档

react-router 6 tutorial