前言:22年12月份结束了实习,在等毕业证的这段时间里,自己也是就感兴趣的地方原理进行了一番学习,实操,之前很多的项目里,要么就是原来配置好的,照葫芦画瓢添加路由,要么就是脚手架集成的,自己想从0-1实现一下基本的路由配置,基于技术与时俱进的原则,这里就 react router v6 探索,后续与 react router v5 版本的差别再好好思考一番。
我的开发环境:mac+vscode+node(v16.20.1)
仓库地址:https://github.com/hyh-op/react-router
基本框架安装
- 脚手架构建一个react+ts 项目。
npx create-react-app react-router --template typescript
- 安装路由v6版本的依赖(安装失败的注意下node版本)
yarn add react-router-dom@6 react-router@6
//npm i react-router-dom@6 react-router@6
- 在index.tsx 中,必须用路由组件包裹APP。
import React from 'react';
import { createRoot } from 'react-dom/client';
import { Provider } from 'react-redux';
import { store } from './app/store';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from "react-router-dom";
import './index.css';
const container = document.getElementById('root')!;
const root = createRoot(container);
root.render(
<BrowserRouter>
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
</BrowserRouter>
);
reportWebVitals();
然后根据页面结构,码出对应的页面
二级路由的页面都如上图所示
两个一级路由的页面(MainLayout页和AccountLayout的页)需要有插槽匹配二级路由,Outlet 组件可以将与子路由相匹配的元素显示出来
import React from "react";
import { Outlet } from "react-router-dom";
const MainLayout: React.FC = (): JSX.Element => {
return (
<div>
MainLayout
<br />
<Outlet />
</div>
);
};
export default MainLayout;
- 用React Router v6 提供的useRoutes hook 搭建路由。
App.tsx页面
import './App.css';
import { useRoutes } from 'react-router';
import { accountRoutes, mainRoutes } from './router/routes';
function App() {
const routing = useRoutes([mainRoutes, accountRoutes]);
return (
<>
{routing}
</>
);
}
export default App;
routes.js路由匹配
import { Navigate } from 'react-router-dom';
import MainView from '../main/MainView';
import MainLayout from '../main/MainLayout'
import PageNotFoundView from '../errror/PageNotFoundView'
import AccountLayout from '../account/AccountLayout'
import AccountDetailView from '../account/AccountDetailView'
import AccountAddView from '../account/AccountAddView'
import AccountListView from '../account/AccountListView'
export const mainRoutes = {
path: '/',
element: <MainLayout />,
children: [
{ path: '*', element: <Navigate to='/404' /> },
{ path: '/', element: <MainView /> },
{ path: '404', element: <PageNotFoundView /> },
{ path: 'account', element: <Navigate to='/account/list' /> },
]
}
export const accountRoutes = {
path: 'account',
element: <AccountLayout />,
children: [
{ path: '*', element: <Navigate to='/404' /> },
// :id 动态参数。
{ path: ':id', element: <AccountDetailView /> },
{ path: 'add', element: <AccountAddView /> },
{ path: 'list', element: <AccountListView /> },
]
}
- 在首页MainLayout 中建立导航栏,用Link 组件实现页面跳转。
MainLayout.tsx页面
import React from "react";
import { Link, Outlet } from "react-router-dom";
const MainLayout: React.FC = (): JSX.Element => {
return (
<div>
MainLayout
<br />
<Outlet />
{/* outlet :嵌套路由,可以保证子路由共享父路由的界面而不会覆盖。
为此React提供了Outlet组件,将其用于父组件中可以为子路由的元素占位,
并最终渲染子路由的元素。 */}
<>
点击连接跳转的部份如下:
{/* nav语义标签 */}
<nav>
<ul>
<li><Link to='/'>Main Page</Link></li>
<li><Link to='/account/add'>Add Account</Link></li>
<li><Link to='/account/list'>List Accounts</Link></li>
<li><Link to='/account/1'>View Account</Link></li>
<li><Link to='/something-else'>Not Found</Link></li>
</ul>
</nav>
<Outlet />
</>
</div>
);
};
export default MainLayout;
若是想用js 跳转页面,要把以前的useHistory 换成useNavigate。
import React from "react";
import { Link, Outlet, useNavigate } from "react-router-dom";
const MainLayout: React.FC = (): JSX.Element => {
let navigate = useNavigate();
return (
<div>
……
<nav>
……
<button
onClick={() => {
navigate("/account/add");
}}
>
Add Account
</button>
</nav>
<Outlet />
</div>
);
};
export default MainLayout;
- 使用useParams hook 可以获取路由传递的参数。
AccountDetailView页面
import React from 'react';
import { useParams } from 'react-router-dom';
const AccountDetailView: React.FC = (): JSX.Element => {
const params = useParams();
return (
<div>
{`View Account ID "${params.id}"`}
</div>
);
};
export default AccountDetailView;
文章评论