React项目初始record

229 阅读2分钟
命令:

npx create-react-app react-ts-app --template typescript

npm i axios sass antd @ant-design/icons react-router-dom redux react-redux redux-persist @reduxjs/toolkit

创建模块
  • Views->
  • Home->
    
  •     Home.tsx
    
  •     Home.modules.scss
    
配置路由

使用BrowserRouter

注: ** react-router-dom 与 react router区别?**

route-> index.ts

import { lazy } from "react";
import { createBrowserRouter } from "react-router-dom";
import type { RouteObject } from "react-router-dom";
import React from "react";
import { CalendarOutlined, CopyOutlined ,FileAddOutlined,ScheduleOutlined,WarningOutlined} from "@ant-design/icons";

const Home = lazy(() => import('../views/Home/Home'))
const Sign = lazy(() => import('../views/Sign/Sign'))
const Exception = lazy(() => import('../views/Exception/Exception'))
const Apply = lazy(() => import('../views/Apply/Apply'))
const Check = lazy(() => import('../views/Check/Check'))
const Login = lazy(() => import('../views/Login/Login'))
// 导航守卫
const BeforeEach = lazy(() => import("../components/BeforeEach/BeforeEach"))

// 扩展meta元信息接口
declare module 'react-router' {
    interface IndexRouteObject {
        meta?: {
            menu?: boolean,
            title?: string,
            icon?: React.ReactNode,
            auth?: boolean
        }
    }

    interface NonIndexRouteObject {
        meta?: {
            menu?: boolean,
            title?: string,
            icon?: React.ReactNode,
            auth?: boolean
        }
    }
}


export const routes: RouteObject[]= [
 {
    path: '/',
    element: React.createElement(BeforeEach, null, React.createElement(Home)),
    meta: {
        menu: true,
        title: '考勤管理',
        icon: React.createElement(CopyOutlined),
        auth: true
    },
    children: [
        {
            path: 'sign',
            element: React.createElement(Sign),
            meta: {
                menu: true,
                title: '在线打卡签到',
                icon: React.createElement(CalendarOutlined),
                auth: true
            },
        },
    ]
 },
 {
    path: '/login',
    element: React.createElement(BeforeEach, null, React.createElement(Login)),
}
]

const router = createBrowserRouter(routes);

export default router;
导航守卫

注: matchRoutes: ?

import React from "react";
import {useLocation, matchRoutes, Navigate} from 'react-router-dom'
import {routes} from '../../router'


interface BeforeEachProps {
    children?:React.ReactNode
}


export default function BeforeEach(props: BeforeEachProps) {
    // 对路由做导航守卫

     const location = useLocation();
     const matchs = matchRoutes(routes, location)

     console.log('location',location);
     console.log('matchs', matchs);
     
    //  由于matchs中的最后一项类型不确定 所以加个类型保护(isArray)
    if( Array.isArray(matchs)) {
        const meta = matchs[matchs.length - 1].route.meta

        // if(meta?.auth) {
        //    return <Navigate to="/login" />
        // }
    }
    return (
        <>
          {props.children}  
        </>
    )
}
封装Axios
import axios from 'axios'
import type { AxiosRequestConfig, AxiosResponse } from 'axios'

// 分装axios
const instance = axios.create({
    baseURL: 'http://localhost:8080',
    timeout: 5000
})

instance.interceptors.request.use(function (config) {
    return config;
}, function (error) {
    return Promise.reject(error)
});

// 添加响应拦截器
instance.interceptors.response.use(function (response) {
    return response
}, function (error) {
    return Promise.reject(error)
})

interface Data {
    [index: string]: unknown
}

interface Http {
    get: (url: string, data?: Data, config?: AxiosRequestConfig) => Promise<AxiosResponse>
    post: (url: string, data?: Data, config?: AxiosRequestConfig) => Promise<AxiosResponse>
    put: (url: string, data?: Data, config?: AxiosRequestConfig) => Promise<AxiosResponse>
    patch: (url: string, data?: Data, config?: AxiosRequestConfig) => Promise<AxiosResponse>
    delete: (url: string, data?: Data, config?: AxiosRequestConfig) => Promise<AxiosResponse>

}

const http: Http = {
    get(url, data, config) {
        return instance.get(url, {
            params: data,
            ...config
        })
    },
    post(url, data, config) {
        return instance.post(url, data, config)
    },
    put(url, data, config) {
        return instance.put(url, data, config)
    },
    patch(url, data, config) {
        return instance.patch(url, data, config)
    },
    delete(url, data, config) {
        return instance.delete(url, {
            data, 
            ...config
        })
    }
}

export default http
配置Redux
  • store->
  •   index.tsx
    
  •   modules->
    
  •       users.tsx
    

注: createSlice: ?

// users.tsx
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import {PayloadAction} from '@reduxjs/toolkit';
import http from "../../utils/http";

type Token = string
type Infos = {
    [index: string]: unknown
}

type UsersState = {
    token: Token
    infos: Infos
}

type Login = {
    email: string
    pass: string
}

// 异步方法
export const loginAction = createAsyncThunk('users/loginAction', async (payload: Login) => {
    const ret = await http.post('/users/login', payload)
    return ret
})

export const infosAction = createAsyncThunk('users/infosAction', async () => {
    const ret = await http.get('/users/infos')
    return ret
})

const usersSlice = createSlice({
    name:'users',
    initialState: {
        token: '',
        infos: {}
    } as UsersState,
    reducers: {
        // 同步方法
        updateToken(state, action: PayloadAction<Token>) {
            state.token = action.payload;
        },
        updateInfos(state, action: PayloadAction<Infos>) {
            state.infos = action.payload;
        },
        clearToken(state) {
            state.token = '';
        }
    }
})

export const {updateToken,updateInfos,clearToken} = usersSlice.actions

export default usersSlice.reducer;
// index.tsx
import { configureStore } from "@reduxjs/toolkit";
// 实现数据持久化的配置操作
import {
    persistStore,
    persistReducer,
    FLUSH,
    REHYDRATE,
    PAUSE,
    PERSIST,
    PURGE,
    REGISTER,
  } from 'redux-persist'
import storage from "redux-persist/lib/storage";

import usersReducer from '../store/modules/users'


const persistConfig = {
    key: 'root',
    version: 1,
    storage,
    whitelist: ['token']
  }
//  blacklist 黑名单数组,可以忽略一些 reducers 中的 key。
//  whitelist 白名单数组,一旦设置,其他的 key 都会被忽略。

const store = configureStore({
    reducer: {
        users: persistReducer(persistConfig,usersReducer)
    },
    middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      serializableCheck: {
        ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
      },
    }),
})
// 持久化
persistStore(store)

export default store;