# 从 5 开始就放弃了原有的 react-router 库,统一命名为 react-router-dom
npm install react-router-dom
HashRouter URL 使用hash(#) 来创建路由
BrowserRouter 采用真实的 URL 资源入口文件 index.js 中引入路由
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
+import { BrowserRouter } from 'react-router-dom';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
+ <BrowserRouter>
<App />
+ </BrowserRouter>
</React.StrictMode>
);
| 组件名 | 作用 | 说明 |
|---|---|---|
| 一组路由 | 代替原来 Switch,所有子路由都用基础的 Router children 来表示 | |
| 基础路由 | Router 可嵌套,解决了原有 v5 中严格模式 | |
| 导航组件 | 在实际页面中跳转使用 | |
| 自适应渲染组件 | 根据实际路由 url 去自动选择组件 |
| hooks名 | 作用 | 说明 |
|---|---|---|
| useParams | 返回当前参数 | 根据路径读取参数 |
| useNavigate | 返回当前路由 | 代替原有 v5 中的 useHistory |
| useOutlet | 返回根据路由生成的 element | |
| useLocation | 返回当前 location 对象 | |
| useRoutes | 同 Routers 组件一样,只不过是在 js 中使用 | |
| useSearchParams | 用来匹配 URL 中 ? 后面的搜索参数 |
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
<Link to="/">home</Link>
<Link to="/about">about</Link>
<Routes>
<Route path="user" element={<Users />}>
<Route path=":id" element={<UserDetail />} />
<Route path="create" element={<NewUser />} />
</Route>
</Routes>
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<About />} />
<Route path="user" element={<User />} />
<Route path="about" element={<About />} />
</Route>
</Routes>
/home
/home/admin
/users/:id
/users/:id/messages
/files/*
/files/:id/*
NotFound 类路由,可以用 * 替代<Routes>
<Route path="/" element={<Home />} />
<Route path="dashboard" element={<Dashboard />} />
<Route path="*" element={<NotFound />} />
</Routes>
useParams 和 useSearchParamsuseParams() 直接返回 param 对象useSearchParams() 返回一个 包含 searchParams 对象、setSearchParams 方法 的对象
searchParams.get(key) 获得参数setSearchParams({key: value}) 来改变路由useNavigate//js写法
let navigate = useNavigate();
function handleClick() {
navigate("/home");
}
//组件写法
function App() {
return <Navigate to="/home" replace state={state} />;
}
//替代原有的go goBack和goForward
<button onClick={() => navigate(-2)}>
Go 2 pages back
</button>
<button onClick={() => navigate(-1)}>
Go back
</button>
<button onClick={() => navigate(1)}>
Go forward
</button>
<button onClick={() => navigate(2)}>
Go 2 pages forward
</button>
需知:如要在父路由中显示嵌套路由中的子路由,需要引入
react-router-dom库中的Outlet组件
BrowserRouter ,启用全局路由// index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import { BrowserRouter } from 'react-router-dom';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
);
src/router/index.js,配置项目路由// index.js
import { lazy, Suspense } from 'react';
const CityList = lazy(() => import("../pages/CityList"));
const AppLayout = lazy(() => import('../pages/AppLayout'));
const Index = lazy(() => import("../pages/Index"));
const News = lazy(() => import('../pages/News'));
const lazyLoad = (children) => {
return <Suspense fallback={<>Loading</>}>
{children}
</Suspense>;
};
const routes = [
{
path: '/',
element: <AppLayout />,
children: [
{
path: '/index',
element: lazyLoad(<Index />)
},
{
path: '/news',
element: lazyLoad(<News />)
}
]
},
{
path: '/cityList',
element: <CityList />
},
];
export { routes };
编写好的 routes// App.js
import './App.css';
import { useRoutes } from 'react-router-dom';
import { routes } from './router/index';
function App() {
return useRoutes(routes);
}
export default App;
使用了react库中的 lazy 配合 Suspense(本质是 promise)
根组件 App.js 中使用 Suspense 组件包裹
import { lazy, Suspense } from 'react';
const AppLayout = lazy(() => import('../pages/AppLayout'));
const Home = lazy(() => import('../pages/Home'));
const CityList = lazy(() => import('../pages/CityList'));
const News = lazy(() => import('../pages/News'));
const routes = [
{
path: '/',
element: <AppLayout />,
children: [
{
index: true,
element: <Home />
},
{
path: 'news',
element: <News />
}
]
},
{
path: '/citylist',
element: <CityList />
}
];
export { routes };
import './App.css';
// UI组件库: antd-mobile
import { Button } from 'antd-mobile';
import { routes } from './router/index';
import { useRoutes } from 'react-router-dom';
import { Suspense } from 'react';
function App() {
let element = useRoutes(routes);
return (
<Suspense fallback={<>loading</>}>
{element}
</Suspense>
);
}
export default App;
/* src/router/index.js */
import { lazy, Suspense } from 'react';
import AppLayout from '../pages/AppLayout';
const Home = lazy(() => import('../pages/Home'));
const CityList = lazy(() => import('../pages/CityList'));
const News = lazy(() => import('../pages/News'));
const lazyLoad = (children) => {
return <Suspense fallback={<>Loading...</>}>
{children}
</Suspense>;
};
const routes = [
{
path: '/',
element: <AppLayout />,
children: [
{
index: true,
element: lazyLoad(<Home />)
},
{
path: 'news',
element: lazyLoad(<News />)
},
{
path: 'citylist',
element: lazyLoad(<CityList />)
},
]
},
];
export { routes };
/* /src/App.js */
import './App.css';
// UI组件库: antd-mobile
import { Button } from 'antd-mobile';
import { routes } from './router/index';
import { useRoutes } from 'react-router-dom';
function App() {
let element = useRoutes(routes);
return element;
}
export default App;
useEffect 该 Hook 类似生命周期函数 componentWillUnmount、componentDidMount 和 componentDidUpdate(可看做是三者的结合)
函数组件(该概念区别于类组件)中执行副作用操作
['data']类组件中经常将不相关的逻辑放在同一个生命周期函数中,将相关的逻辑分离在多个不同的生命周期函数中 的这个问题useEffect 来分离这些需要在各个生命周期函数中处理的逻辑
import './App.css';
// UI组件库: antd-mobile
import { Button } from 'antd-mobile';
import { routes } from './router/index';
import { useRoutes, useLocation } from 'react-router-dom';
import { Suspense, useEffect } from 'react';
function App() {
const location = useLocation();
useEffect(() => {
console.log(location.pathname, 'enter: 路由前置守卫');
return () => {
console.log(location.pathname, 'leave: 路由后置守卫');
};
}, [location.pathname]);
let element = useRoutes(routes);
return element;
}
export default App;
函数组件 中实现类似 setState() 的效果
const [count, setCount] = useState('banana')setCount(new value) 来实现状态更新路由监听操作 封装成一个函数传递给 App.js 根组件/* /src/router/index.js */
import { lazy, Suspense } from 'react';
import { matchRoutes } from 'react-router-dom';
import AppLayout from '../pages/AppLayout';
import NotFound from '../pages/NotFound';
const Home = lazy(() => import('../pages/Home'));
const CityList = lazy(() => import('../pages/CityList'));
const News = lazy(() => import('../pages/News'));
const lazyLoad = (children) => {
return <Suspense fallback={<>Loading...</>}>
{children}
</Suspense>;
};
const routes = [
{
path: '/',
element: <AppLayout />,
children: [
{
index: true,
element: lazyLoad(<Home />)
},
{
path: 'news',
element: lazyLoad(<News />)
},
{
path: 'citylist',
element: lazyLoad(<CityList />)
},
]
},
{
path: '/404',
element: <NotFound />
}
];
const routerListener = (path, navigator) => {
return () => {
const isMatch = matchRoutes(routes, path);
if (!isMatch) {
navigator('/404');
}
console.log(path, 'enter: routerEnterEvent');
return () => {
console.log(path, 'leave: routerLeaveEvent');
};
};
};
export { routes, routerListener };
/* App.js */
import './App.css';
// UI组件库: antd-mobile
import { Button } from 'antd-mobile';
import { routes, routerListener } from './router/index';
import { useRoutes, useLocation, useNavigate } from 'react-router-dom';
import { useEffect, useState } from 'react';
function App() {
const location = useLocation();
const navigator = useNavigate();
let [pathname, setPathname] = useState(location.pathname);
useEffect(
routerListener(pathname, navigator),
[pathname]
);
let element = useRoutes(routes);
return element;
}
export default App;