路由和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-native 用于React Native, 处理手机app的路由
- react-router-redux 提供了路由中间件,处理redux的集成
- react-router-config 用来静态配置路由
安装react-router-dom
yarn add react-router-domyarn add --dev @types/react-router-dom
BrowserRouter 和 HashRouter的区别:
- BrowserRouter的url不带#, 请求不同的页面都是不同的url, 服务器需要对每个url都做响应配置
- HashRouter带#, #后的内容不会传给服务器,服务器始终响应一个url
react-router已经升级到了v6, 查看详细变化
使用react-router(这里是react-router最新版本6的用法)
// react-router 6 写法import styles from './App.module.css'import { BrowserRouter, Routes, Route } from 'react-router-dom'import { HomePage, SignInPage, RegisterPage, DetailPage } from './pages'function App() {return (<div className={styles.App}><BrowserRouter><Routes><Route path="/" element={<HomePage />} /><Route path="/signIn" element={<SignInPage />} /><Route path="/register" element={<RegisterPage />} /><Route path="/detail/:id" element={<DetailPage />} /><Route path="*" element={<div>404 not found</div>} /></Routes></BrowserRouter></div>)}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;
<a name="s2orp"></a>#### 如何在URL中添加参数?- 第一种使用query string: http://localhost/path?name1=value1&name2=value2- 第二种使用Restful ID: http://localhost/path/:userid在组件中获取url 参数```tsximport { useParams } from 'react-router'export const DetailPage = () => {const { touristRouteId } = useParams()return <h1>产品详情, ID: {touristRouteId}</h1>}
在 react-router 5 中是可以通过 props 获取参数的,6 已经不可以了
import React from "react";import { RouteComponentProps } from "react-router-dom";interface MatchParams {touristRouteId: string;}export const DetailPage: React.FC<RouteComponentProps<MatchParams>> = (props) => {// console.log(props.history);// console.log(props.location);// console.log(props.match);return <h1>路游路线详情页面, 路线ID: {props.match.params.touristRouteId}</h1>;};
useHistory VS useNavigate
在 react-router 5 中,通过操作 history 实现跳转
// This is a React Router v5 appimport { useHistory } from "react-router-dom";function App() {let history = useHistory();function handleClick() {history.push("/home");}return (<div><button onClick={handleClick}>go home</button></div>);}
而在 react-router 6 中使用新的API navigate实现跳转
// This is a React Router v6 appimport { useNavigate } from "react-router-dom";function App() {let navigate = useNavigate();function handleClick() {navigate("/home");}return (<div><button onClick={handleClick}>go home</button></div>);}
用 navigate(to, { replace: true }) 替代 history.replace(to)
Redirect VS Navigate
react-router 5 中使用 Redirect 实现路由重定向
<Redirect to="about" /> // 默认是replace<Redirect to="home" push />
react-router 6 中使用 Navigate 实现路由重定向
<Navigate to="about" replace /><Navigate to="home" /> // 默认是push
Link
Link也可以实现跳转
<Link to="/invoices">Invoices</Link><Link to="/expenses">Expenses</Link>
原理
interface LinkProps {to: string;}const Link: React.FC<LinkProps> = ({children, to}) => {const history = useHistory()return (<a href={to} onClick={()=>{history.push(to)}}>{children}</a>)}
