v6 版本相对比前面有较大修改
安装
1
| yarn add react-router-dom
|
基本使用
常用方法
Routes
新版本 Routes 替代了 Switch,并且 Routes 和 Route 必须关联,
Route 内可以直接嵌套子路由.子路由的位置可以由Outlet
组件占位.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| import { Routes , Route , Outlet } from 'react-router import { BrowserRouter } from 'react-router-dom' const index = () => { return <div className="page" > <div className="content" > <BrowserRouter > <Menus /> <Routes> <Route element={<Home />} path="/home" ></Route> <Route element={<List/>} path="/list" ></Route> <Route element={<Layout/>} path="/children" > <Route element={<Child1/>} path="/children/child1" ></Route> <Route element={<Child2/>} path="/children/child2" ></Route> </Route> </Routes> </BrowserRouter> </div> </div> }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| function Container() { return ( <div> {" "} <Outlet /> </div> ); }
function Menus1() { return ( <div> <Link to={"/children/child1"}> child1 </Link> <Link to={"/children/child2"}> child2 </Link> </div> ); }
function Layout() { return ( <div> 这里是 children 页面 <Menus1 /> <Container /> </div> ); }
|
路由状态和页面跳转
Link
1
| <Link to="/invoices">Invoices</Link>
|
Link 与 a 标签的区别?
Link 避免了重新渲染。Link 只会触发相匹配路由页面的更新,不会刷新整个页面。
Link 所做的事:
- 有 onClick 就执行 onClick
- click 的时候阻止 a 标签默认事件
- 根据跳转的 href,使用 history 跳转,只是链接变了,并不刷新整个页面
useLocation
可以使用 useLocation 获取到路由状态 location 的信息,这里保存了hash | key | pathname | search | state
等状态.
useNavigate
1 2 3 4 5 6 7 8
| function Home() { const navigate = useNavigate(); return <> <button onClick={() => navigate('/list', { state: 'alien'})}> 跳转列表页 </button> <> }
|
navigate
第一个参数是路径,第二个是路由状态信息,可以传递state
等信息.
useParams
动态路由
通过useParams
获取 url 上的动态路由信息
1
| <Route element={<List />} path="/list/:id" />
|
跳转动态路由:
1
| <button onClick={() => navigate("/lsit/1")}>跳转列表页</button>
|
获取动态参数
1 2 3 4 5
| function List() { const params = useParams(); console.log(params, "params"); return <div>React yes!</div>; }
|
useSearchParams
用于 url 参数信息获取或设置.
const [searchParams, setSearchParams] = useSeatchParams()
方法中 searchParams 可以获取 params 中的 url 信息,第二个可以设置.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| function Index() { const [searchParams, setSearchParams] = useSeatchParams(); const name = search.get("name"); return ( <> <button onClick={() => { setSearchParams({ name: "alien", age: 22 }); }} > 设置params </button> </> ); }
|
区别
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| const Detail = (props) => {
const detail = useUrlQueryParam(["id", "title"]); console.log("获取到对象:", detail);
return ( <ul> <li>ID:{detail.id}</li> <li>TITLE:{detail.title}</li> <li> CONTENT:{detail.title}+{detail.id} </li> </ul> ); };
export default Detail;
export const useUrlQueryParam = (keys) => { const [search] = useSearchParams(); const query = keys.reduce((acc, key) => { acc[key] = search.get(key); return acc; }, {}); return query; };
|
useRoutes
用于自由配置路由
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| const routeConfig = [ { path: "/home", element: <Home />, }, { path: "/list/:id", element: <List />, }, { path: "/children", element: <Layout />, children: [ { path: "/children/child1", element: <Child1 /> }, { path: "/children/child2", element: <Child2 /> }, ], }, ];
const Index = () => { const element = useRoutes(routeConfig); return ( <div className="page"> <div className="content"> <Menus /> {element} </div> </div> ); };
const App = () => ( <BrowserRouter> <Index /> </BrowserRouter> );
|
疑难问题
axios 内部只是不能调用 hook,因为 hooks 的定义就是只能在函数组件顶层或其他 hook 内部调用。
解决办法:先在 axios 方法外调用 useNavigate 钩子得到 nav 方法,然后在 axios 回调里用 nav 方法进行路由跳转
Navigate 组件应该是放在业务组件里。比如路径/a 要跳转到路径/b,则是放在路径/a 对应的 A 组件里,不是放在 routes 里面
原理
BrowserRouter
- 通过 createBrowserHistory 创建 history 对象,并通过 useRef 保存 history 对象。
- 通过 useLayoutEffect 来监听 history 变化,当 history 发生变化(浏览器人为输入,获取 a 标签跳转,api 跳转等 )。派发更新,渲染整个 router 树。这是和老版本的区别,老版本里面,监听路由变化更新组件是在 Router 中进行的。
- 还有一点注意的事,在老版本中,有一个 history 对象的概念,新版本中把它叫做 navigator 。
不使用
exact
取消了,所有路由默认都是严格匹配,如果想模糊匹配,可以在路由后加*
新增数据路由
主要是针对数据的新增一些 api。
比如 createBrowser 之类。
loader 方法,在路由加载之前可以用来请求数据。
errorElement:错误组件,路由通过 useRoutesError 返回错误信息,可以调用这个组件。只在使用数据路由时生效。