后台管理系统之工具包的引入

我们会集成以下内容

  • react-router redux
  • antd
  • axios
pnpm add react-router redux-react @reduxjs/toolkit antd axios
配置路由
  1. 采用单独配置文件的方式, 在src文件夹下创建router,并在其中index.tsx中配置
import type { RouteObject } from "react-router-dom";
import { Navigate } from "react-router-dom";
import Home from "../views/Home";
import Login from "../views/Login";

const routes: RouteObject[] = [
  {
    path: "/",
    // 访问根路径重定向到home
    element: <Navigate to={"/home"} />,
  },
  {
    path: "/home",
    element: <Home />,
  },
  {
    path: "/login",
    element: <Login />,
  },
];
export default routes;

  1. App.tsx使用routes,使用useRoutesroutes导入

用法可参考文档:useRoutes v6.4.1 | React Router

	import React from "react";
	import { useRoutes } from "react-router-dom";
	import routes from "./router";
	const App = () => {
	  return (
	    <div className="App">
	      <h1>Hello react</h1>
	      <div>{useRoutes(routes)}</div>
	    </div>
	  );
	};
  1. src下的index.tsx中开启路由模式,这里使用的是BrowserRouter
import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
// 或者 HashRouter
import App from "./App";

const root = ReactDOM.createRoot(
  document.querySelector("#root") as HTMLElement,
);
root.render(
  <React.StrictMode>
    <BrowserRouter>
        <App />
    </BrowserRouter>
  </React.StrictMode>,
);

  1. 然后在App.tsx添加跳转路由的按钮即可
import React from "react";
import { Link, useRoutes } from "react-router-dom";
import routes from "./router";
const App = () => {
  return (
    <div className="App">
      <h1>Hello react</h1>
      <div>{useRoutes(routes)}</div>
      <Link to="/home">Home</Link>
      <Link to="/login">Login</Link>
    </div>
  );
};
配置redux

Redux Toolkit是官方推荐的编写 Redux 逻辑的方法

  1. store文件夹下的index.ts中创建store
import { configureStore } from "@reduxjs/toolkit";

const store = configureStore({
  reducer: {},
});
// 获取到根的state类型,方便后面使用
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
export default store;

使用RTK提供的 configureStore方法来创建

  1. 在外界使用我们创建的store,也就是App.tsx

RTK 提供Provider让我们使用创建的store,这样后面就可以使用了

import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import { Provider } from "react-redux";

import App from "./App";
import store from "./store";

const root = ReactDOM.createRoot(
  document.querySelector("#root") as HTMLElement,
);
root.render(
  <React.StrictMode>
    <BrowserRouter>
      <Provider store={store}>
        <App />
      </Provider>
    </BrowserRouter>
  </React.StrictMode>,
);

  1. 为了方便一会测试,这里我们创建一个reducer用于储存一个计数器的状态,结构目录如下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P9h0yEVI-1666933285137)(E:\code\react\my-admin\README.assets\image-20221028111920964.png)]

mainReducer.ts内容如下

import { createSlice } from "@reduxjs/toolkit";
import { RootState } from "../index";

const initialState = { // 初始状态
  count: 0,
};
// createSlice用于创建切片
const mainSlice = createSlice({
  name: "main",
  initialState,
  reducers: {
    // 定义reducer
    increment: (state) => {
      state.count++;
    },
    decrement: (state) => {
      state.count--;
    },
  },
});
// 将定义的方法解构导出方便外面使用
export const { increment, decrement } = mainSlice.actions;
// 直接将 coute的值取出,调用该方法直接拿到count的值,rootState是 store的状态类型,在上面定义过
export const selectCount = (state: RootState) => state.main.count;
export default mainSlice.reducer;
  1. 在 store中使用这个reducer
import { configureStore } from "@reduxjs/toolkit";
import mainReducer from "./reducer/mainReducer";

const store = configureStore({
  // 创建 store
  reducer: {
    main: mainReducer,
  },
});
// 获取到根的state类型,方便后面使用
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
export default store;

  1. 在页面中进行使用
    • 通过调用selectCount拿到count
    • 引入count的两个方法increment decrement
import { decrement, increment, selectCount } from "store/reducer/mainReducer";
import { Button } from "antd";
import { useAppDispatch, useAppSelector } from "store/hooks";
import React from "react";

const Home = () => {
  const dispatch = useAppDispatch();
  return (
    <div className="home">
      <h1>Home Page</h1>
      <h3>{useAppSelector(selectCount)}</h3>
      <button onClick={() => dispatch(decrement())}>-</button>
      <button onClick={() => dispatch(increment())}>+</button>
    </div>
  );
};
export default Home;

这里用到了 hooks 中的两个方法,是为了增强类型推断,所以就算使用 原来的 useDispatch, useSelector也没问题,如下

import React from "react";
import { useDispatch, useSelector } from "react-redux";
import { decrement, increment, selectCount } from "store/reducer/mainReducer";

const Home = () => {
   // 用于创建一个dispatch函数
  const dispatch = useDispatch();
  return (
    <HomeWrap>
      <h1>Home Page</h1>
      <h3>{useSelector(selectCount)}</h3>
      <button onClick={() => dispatch(decrement())}>-</button>
      <button onClick={() => dispatch(increment())}>+</button>
    </HomeWrap>
  );
};
export default Home;

hooks.ts内容如下

import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
import type { AppDispatch, RootState } from "./index";

//自定义hook,调用该方法返回一个 dispatch,用于派发action
const useAppDispatch = () => useDispatch<AppDispatch>();
// 为rootstate,创建有更好的类型校验的 useSelector,之后用该方法代替 useSelector就好
const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
export { useAppDispatch, useAppSelector };
引入antd

antd的引入就相对于简单些,安装完依赖之后在src下的index.tsx引入antd/dist/antd.css即可,而antd默认js部分就支持按需引入,所以在哪要使用组件直接引入就可以了

pnpm add antd

我们在上面的Home中两个按钮使用 antd提供的作为测试

import React from "react";
import { useDispatch, useSelector } from "react-redux";
import { Button } from "antd";

import { decrement, increment, selectCount } from "store/reducer/mainReducer";

const Home = () => {
  const dispatch = useDispatch();
  return (
    <HomeWrap>
      <h1>Home Page</h1>
      <Counter>{useSelector(selectCount)}</Counter>
      <Button onClick={() => dispatch(decrement())}>-</Button>
      <Button onClick={() => dispatch(increment())}>+</Button>
    </HomeWrap>
  );
};
export default Home;

集成axios
  1. 安装依赖
pnpm add axios
# 因为是ts 所以我们还需要安装类型声明
pnpm add -D @types/axios
  1. axios进行二次封装,结构目录如下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QRBvmozF-1666933285139)(E:\code\react\my-admin\README.assets\image-20221028124536434.png)]

request中封装一个 Request类,用于项目中的网络请求

import axios, { AxiosInstance, AxiosRequestConfig } from "axios";
import { config } from "./config";

class Request {
  instance: AxiosInstance;

  constructor(config: AxiosRequestConfig) {
      // 重新创建一个 axios实例
    this.instance = axios.create(config);
  }

  async request(config: AxiosRequestConfig) {
    return this.instance.request(config);
  }

  post(config: AxiosRequestConfig) {
    return this.request({ ...config, method: "post" });
  }

  get(config: AxiosRequestConfig) {
    return this.request({
      ...config,
      method: "get",
    });
  }
}

export default new Request(config);
// config.ts 内容
const config = {
    // 这里因为跨域了,所以写/api,关于跨域的解决后面说
  baseURL: "/api",
  timeout: 3000,
};
export { config };

这里先只是最简单的请求方法,关于拦截器,后面用到了再加上

  1. 测试:在api下创建login.ts模块作为测试,内容如下
import request from "../request";

const login = async () => {
  return await request.post({
    url: "admin/login",
    data: {
      username: "admin",
      password: "admin",
    },
  });
};
export default login;
  1. 在App中发送请求
import React from "react";
import { Link, useRoutes } from "react-router-dom";
import routes from "./router";
import { login } from "./service";

const fn = () => {
  login().then((res) => {
    console.log(res);
  });
};

const App = () => {
  return (
    <div className="App">
      <Title>Hello react</Title>
      <button onClick={fn}>发送请求</button>
      <Wrap>{useRoutes(routes)}</Wrap>
      <Link to="/home">
        <Button>Home</Button>
      </Link>
      <Link to="/login">
        <Button>Login</Button>
      </Link>
    </div>
  );
};

export default App;
测试
  1. 启动项目
    在这里插入图片描述

  2. 点击切换路由到login

在这里插入图片描述3. 在home中点击 antd 按钮
在这里插入图片描述
4 .发送请求
在这里插入图片描述

结束语

到现在就大概完成了所有的配置,之后就正式开始后面的内容,嗷还有一个关于create-react-app创建的项目跨域问题,解决如下

  1. 安装中间件:http-proxy-middleware
  2. 在***src***文件夹下创建文件 setupProxy.js

一定要在 src下,我放根目录,找半天不知道为啥不生效;不用再任何地方引入,启服务时自己会加载
官网有说:跨域的解决

  1. 内容如下
const { createProxyMiddleware } = require("http-proxy-middleware");

module.exports = (app) => {
  app.use(
    createProxyMiddleware("/api", {
      target: "http://ceshi13.dishait.cn/",
      changeOrigin: true,
      pathRewrite: {
        "^/api": "/",
      },
    }),
  );
};

访问 以 /api 开头的路径时,请求targeturl,这也是为什么前面 axios 配置中写/api的原因,pathRewrite的作用将 /api从真实的路径中去除,以免影响;当然后端真是/api开头的那当我没说

后面我会使用styled-components来进行组件样式的编写,可以先安装一下依赖

pnpm add styled-components
pnpm add @types/styled-components -D

用法参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值