react-实战(二)

261 阅读3分钟

上会整理了react+ts项目初始化和添加craco配置,这回梳理react-router和网络请求封装,以及antd的使用

1.安装router和配置router antd

router使用的版本是6.8.1

1.安装依赖 npm install react-router-dom npm install antd

2.配置路由

src下创建router目录,里面创建config.tsx配置文件,可以将所有路由配置在这里,也可以编写路由拦截

import { lazy } from "react";
import { Navigate } from 'react-router-dom'
import Layout from '@/components/Layout';
const lazyLoad = (moduleName: string) => {
    const Module = lazy(() => import(`@/views/${moduleName}`));
    return <Module />;
};
// 路由拦截组件
const Approve = ({ children }: any) => {
    const token = sessionStorage.getItem("token");
    return token ? children : <Navigate to="/login" />;
  };
const routeConfig=[
    {
        path:"/login",
        element:lazyLoad("login"),
        auth: false
    },
    {
        path:"/",
        element:<Approve><Layout /></Approve>,
        auth: false,
        children:[
            {
                path:"/",
                element:lazyLoad("home"),
                auth: false
            },
            {
                path:"/other",
                // element:lazyLoad("other"),
                auth: false,
                children:[
                    {
                        path:"/other/other1",
                        element:lazyLoad("other"),
                        auth: false,
                    },
                    {
                        path:"/other/other2",
                        element:lazyLoad("other"),
                        auth: false,
                    }
                ]
            },
            {
                path:"/mine/:id",
                element:lazyLoad("mine"),
                auth: false
            },
            {
                path:"/dashboard",
                element:lazyLoad("dashboard"),
                auth: false
            },
        ]
    },
    {
        path: "*",
        element: lazyLoad("not-found"),
    },
    
    
]
export default routeConfig
​

3.路由嵌套

Outlet 类似于vue 的router-view,用于路由嵌套

import React,{ FC,useState } from 'react';
import {
  MenuFoldOutlined,
  MenuUnfoldOutlined,
  AndroidOutlined
} from '@ant-design/icons';
import { Outlet } from 'react-router-dom'
import { Layout, theme,Space } from 'antd';
import './Layout.css'
import Menu from '@/components/Menu'
import {menuMode} from '@/const/config'const { Header, Content, Footer, Sider } = Layout;
const App: FC = () => {
  const {
    token: { colorBgContainer },
  } = theme.useToken();
  const [collapsed, setCollapsed] = useState(false);
  const [bool,setBool]=useState(menuMode=='horizontal')
  return (
    <Layout style={{height:'100%'}}>
      {bool?<Menu/>:
      <Sider
        trigger={null} collapsible collapsed={collapsed}
      >
        <div id="logo"><AndroidOutlined /><span>XXXXXXX系统</span></div>
        <Menu/>
      </Sider>
      }
      <Layout className="site-layout">
      {bool?'':
        <Header style={{ padding: 0,paddingLeft:'20px',textAlign:'left', background: colorBgContainer }}>
          <Space>{React.createElement(collapsed ? MenuUnfoldOutlined : MenuFoldOutlined, {
            className: 'trigger',
            onClick: () => setCollapsed(!collapsed),
          })}
          
          </Space>
        </Header>
      }
        <Content style={{ }}>
          <div style={{ marginLeft: bool?0:10,marginTop:bool?0:10, minHeight: 360,height:'100%', background: colorBgContainer }}>
            <Outlet />
          </div>
        </Content>
        <Footer style={{ textAlign: 'center' }}>Ant Design ©2023 Created by Ant UED</Footer>
      </Layout>
    </Layout>
  )
  
​
};
​
export default App;

4.修改app.tsx

import {useRoutes } from 'react-router-dom';
import './App.css';
import routerConfig from './router/config'
function App() {
  const element =useRoutes(routerConfig)
  return (
    <div className="App">
        {element}
    </div>
  );
}
​
export default App;
​

5.修改index.tsx

import React from 'react';
import { Provider } from 'react-redux'
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import store from '@/store'
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import Loading from "views/loading";
import './utils/global'const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);
root.render(
  <React.StrictMode>
    <Provider store={store}>
    <BrowserRouter>
    <React.Suspense fallback={<Loading />}><App /></React.Suspense>
    
    </BrowserRouter>
    </Provider>
   </React.StrictMode>
);
​
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

6.路由跳转和传参

menu.tsx

import React, { useState } from 'react';
import { BankOutlined,GithubOutlined,CiOutlined,AreaChartOutlined } from '@ant-design/icons';
import {useNavigate } from 'react-router-dom'
import type { MenuProps } from 'antd';
import {Menu} from 'antd'
import {menuMode} from '@/const/config'
import './index.less'
const items: MenuProps['items'] = [
  {
    label: '首页',
    key: '/',
    icon: <BankOutlined />,
  },
  
  {
    label: '测试',
    key: '/other',
    icon: <CiOutlined />,
    children:[
      {
        label: '测试1',
        key: '/other/other1',
      },
      {
        label: '测试2',
        key: '/other/other2',
      },
    ]
  },
  {
    label: '图表',
    key: '/dashboard',
    icon: <AreaChartOutlined />,
    disabled: false,
    children:[
      {
        label: '测试1',
        key: '/other/other1',
      },
      {
        label: '测试2',
        key: '/other/other2',
      },
    ]
  },
  {
    label: '我的',
    key: '/mine/10?a=10&b=20',
    icon: <GithubOutlined />,
  },
  {
    label: (
      <a href="https://ant.design" target="_blank" rel="noopener noreferrer">
        Navigation Four - Link
      </a>
    ),
    key: 'alipay',
  },
];
​
const App: React.FC = () => {
  const [current, setCurrent] = useState('/');
  const [mode, setMode] = useState(menuMode);
  const navigate = useNavigate()
  const onClick: MenuProps['onClick'] = (e) => {
    console.log('click ', e);
    setCurrent(e.key);
    navigate(e.key, { state:{name:'jerrry',age:10}, })
  };
​
  return <Menu className="mstye" onClick={onClick} selectedKeys={[current]} mode={mode} theme="dark" items={items} />;
};
​
export default App;

7.几种路由传参总结

import { useLocation,useParams ,useNavigate } from 'react-router-dom'
const navigate = useNavigate()
navigate('/path/', { state:{name:'jerrry',age:10}, })
// 需要动态路由配合 /login/:id/:age
let pp=useParams()
接收到的是{id:10,age:20}
// 可以拿到 state 和 search /path?a=10&b=20
let ap=useLocation()
接收的是路由对象 包含search和state
pathname: "/mine"
search: "?a=10&b=20"
state: {name: 'jerrry', age: 10}

2.axios封装和使用

封装axios

import axios from "axios";
import NProgress from "nprogress";
import { message } from "antd";
​
​
import { BASE_URL, TIMEOUT } from "@/const/config";
​
const instance = axios.create({
  baseURL: BASE_URL,
  timeout: TIMEOUT,
});
​
instance.interceptors.request.use(
  (config) => {
    // 1.发送网络请求时, 在界面的中间位置显示Loading的组件
    NProgress.start();
    // 2.某一些请求要求用户必须携带token, 如果没有携带, 那么直接跳转到登录页面
​
    // 3.params/data序列化的操作
    return config;
  },
  (err) => {
    console.log(err);
  }
);
​
instance.interceptors.response.use(
  (res) => {
    NProgress.done();
    return res.data;
  },
  (err) => {
    if (err && err.response) {
      switch (err.response.status) {
        case 400:
          console.log("请求错误");
          break;
        case 401:
          console.log("未授权访问");
          break;
        default:
          console.log("其他错误信息");
      }
    }
    message.error("当前网络异常,请稍后重试");
    NProgress.done();
    return err;
  }
);
​
export default instance;
​

再创建api.ts 在这里写具体的请求,哪里需要就从这里引用

import http from './http'
const api ={
    queryList(o:Object){
​
        return http({
            url:'/queryList',
            method:'get',
            params:o
        })
    }
} 
export default api
​
import api from '@/utils/api'
api.queryList({}).then(res=>{
      console.log('----ooo',res)
})