react ts

一、项目搭建

1、创建项目

  • 使用vite生成项目

npx create-react-app react-ts-project --template typescript
  • 启动项目

yarn start
  • 删除无用组件

2、设计目录结构

资源说明
http网络请求
assets公共资源
components组件
router路由配置
utils工具模块
store状态机
App.tsx应用根组件
index.tsx入口ts文件

3、配置sass环境

  • 安装sass包

yarn add sass
  • 创建全局样式文件

4、craco插件配置

如果要修改CRA的默认配置,有以下几种方案

  • 通过第三方库来修改,比如@craco/craco

  • 通过执行yarn eject命令,释放react-scripts中的所有配置到项目中

实现步骤

  • 安装修改CRA的配置的包

yarn add -D @craco/craco
  • 在项目的根目录中创建craco的配置文件(craco.config.js),并在配置中配置别名

const path=require('path')
module.exports={webpack:{alias:{'@':path.resolve(__dirname,'src')}}
}
  • 修改packge.json中的脚本命令

"scripts": {"start": "craco start","build": "craco build","test": "craco test","eject": "react-scripts eject"}
  • 在代码中,就可以通过@来表示src目录的绝对路径

  • 重启项目,让配置生效

@别名路径提示

  • 在项目根目录创建tsconfig.json配置文件

  • 在配置文件中添加如下配置

{"compilerOptions": {"baseUrl": "./","paths": {"@/*": ["src/*"]}}}

5、配置路由

  • 安装路由

yarn add react-router-dom
yarn add react-loadable
yarn add @types/react-loadable

下载react-loadable依赖包进行路由懒加载,如果你是typescript,你还需要额外安装@types/react-loadable这个依赖包

  • 建立一个loadable.ts,放在src/utils/loadable.ts

import Loadable from 'react-loadable';
export default function withLoadable(comp:any) {return Loadable({//懒加载组件页面loader: comp,loading: () => null})
}
  • 在src下创建router目录,在该目录的index.tsx编写路由配置文件

import loadable from '@/utils/loadable'
import {RouteObject} from 'react-router-dom'
const Login=loadable(()=>import('@/views/Login'))
const Home=loadable(()=>import('@/views/Home'))
const Main=loadable(()=>import('@/views/Main'))
const Product=loadable(()=>import('@/views/Product'))
const Category=loadable(()=>import('@/views/Category'))
const routes:Array<RouteObject>=[{path:'/login',element:<Login/>},{path:'/',element:<Home/>,children:[{index:true,element:<Main></Main>},{path:'product/list',element:<Product></Product>}, {path:'product/category',element:<Category></Category>}]}
]
export default routes
  • 在App.tsx中通过useRoutes钩子函数来进行集中式配置

import React,{Suspense} from 'react'
import {useRoutes} from 'react-router-dom'
import routes from '@/router'
export default function App() {return (<Suspense fallback={<>loading</>}>{useRoutes(routes)}</Suspense>)
}
  • 在项目根目录下的index.tsx中使用<BrowserRouter>包裹<App>

root.render(<BrowserRouter><App/></BrowserRouter>
)
  • 在src/Home.tsx组件中配置二级路由出口

import React from 'react'
import {Outlet} from 'react-router-dom'
export default function Home() {return (<div>Home<Outlet></Outlet></div>)
}

6、安装AntD

  • 安装AntD组件库

yarn add antd

二、用户登录

1、登录静态页面实现

  • 首先在utils目录下创建type.ts文件,这个文件里主要编写接口

export interface IUser{account:string,password:string}
  • 在views目录下的Login.tsx文件中编写登录的静态页面

import {Button,Form,Input,message} from 'antd'
import api from '@/api'
import {useNavigate} from 'react-router-dom'export default ()=>{const nav=useNavigate()const onFinish=async(values:any)=>{console.log(values)}return (<Form onFinish={onFinish} style={{ maxWidth: 600 }}><Form.Item label='用户名' name="username"><Input/></Form.Item><Form.Item label='密码' name="password"><Input.Password/></Form.Item><Form.Item><Button type="primary" htmlType='submit'>登录</Button></Form.Item></Form>)
}

2、axios的二次封装

import axios,{ InternalAxiosRequestConfig,AxiosResponse,AxiosError} from "axios";
import {message} from 'antd'
//设置根路径
axios.defaults.baseURL="http://www.zhaijizhe.cn:3005"
//设置请求拦截器
axios.interceptors.request.use((config: InternalAxiosRequestConfig)=>{const token=localStorage.getItem('token')if(token){config.headers.Authorization=token}return config
})
//设置响应拦截器
axios.interceptors.response.use((response:AxiosResponse)=>{return response.data
},(error:AxiosError)=>{switch(error.response?.status){case 500:message.error('服务端出现500错误')breakcase 401:message.error('服务端出现400错误')break;case 404:message.error("没有找到服务端相应资源");break;}return Promise.reject(error)
})
export default axios

3、登录功能的实现

  • 在src/types文件夹下编写接口

export default interface IUser{username:stringpassword:string
}
  • 编写登录的后端请求API

import request from '@/utils/request'
import IUser from '@/types/IUser'export default{login:(user:IUser)=>request.post('/users/login',user)
}
  • 将用户模块汇总到api.tsx中

import users from "./modules/users"
export default{users
}
  • 在登录组件中调用登录API,完成登录功能

import {Button,Form,Input,message} from 'antd'
import api from '@/api'
import {useNavigate} from 'react-router-dom'export default ()=>{const nav=useNavigate()const onFinish=async(values:any)=>{const result=await api.users.login(values)if(result.data.code){localStorage.setItem('token',result.data.token)nav('/')}else{message.warning('登录失败')}}return (<Form onFinish={onFinish} style={{ maxWidth: 600 }}><Form.Item label='用户名' name="username"><Input/></Form.Item><Form.Item label='密码' name="password"><Input.Password/></Form.Item><Form.Item><Button type="primary" htmlType='submit'>登录</Button></Form.Item></Form>)
}

三、路由权限

1、静态菜单

import {Outlet,NavLink,useNavigate} from 'react-router-dom'
import React,{useState,useEffect} from 'react'
import '@/assets/css/home.scss'
import {Layout,Menu} from 'antd'
import {WindowsOutlined,TrademarkCircleOutlined,UserOutlined} from '@ant-design/icons'
const {Header,Sider,Content,Footer}=Layout
export default ()=>{const[menuList,setMenuList]=useState<any>([])const nav=useNavigate()useEffect(()=>{const list=[{key:'sub1',label:'日常业务',icon:<WindowsOutlined />,children:[{label:'学员管理',key:'/students'},{label:'班级管理',key:'/classes'}]},{key:'sub2',label:'校区管理',icon:<TrademarkCircleOutlined />,children:[{label:'教师管理',key:'/teachers'},{label:'班主任管理',key:'/directors'},{label:'专业管理',key:'/subjects'}]},{key:'sub3',label:'系统管理',icon:<UserOutlined />,children:[{key:'/users',label:'用户管理'}]}]setMenuList(list)},[])const go=(item:any)=>{nav(item.key)}return (<><Layout><Header><div>蜗牛BOSS管理系统</div></Header>  <Layout style={{height:'750px'}}><Sider><Menu items={menuList} onClick={go}mode="inline"theme="dark"defaultOpenKeys={['sub1','sub2']}defaultSelectedKeys={['/home/students']}></Menu></Sider><Content>{/* 设置子路由出口 */}<Outlet></Outlet></Content></Layout><Footer style={{ textAlign: 'center'}}>Ant Design ©2023 Created by Ant UED</Footer></Layout> </>)
}

2、动态菜单

  • 在api/modules/users下编写获取权限菜单的接口

import request from '@/utils/request'
export default{getAuthMenus:()=>request.get('/menus/getAuthMenus')
}
  • 在Home.tsx中中调用getAuthMenus接口来完成权限菜单数据的获取

 useEffect(() => {getAuthMenus()}, [])const getAuthMenus = async () => {const result = await api.users.getAuthMenus()console.log(result.data.data)const rList = transformDataToMenus(result.data.data)setMenuList(rList)}
  • 将后台的权限菜单数据转成antd格式的菜单数据

/*** 将后台的权限菜单数据转成antd格式的菜单数据*/interface IMenuData {title: stringpath: stringicon: stringchildren?: Array<IMenuData>}interface IMenu {label: stringkey: stringicon: ReactElementchildren?: Array<IMenu>}const transformDataToMenus = (list: Array<IMenuData>) => {return list.map((item: IMenuData) => {let name = item.icon as stringlet iis: any = icons[name as keyof typeof icons]let menuItem: IMenu = { label: item.title, key: item.path, icon: React.createElement(iis) }if (item.children) {menuItem.children = transformDataToMenus(item.children)}return menuItem})}
  • 渲染导航列表

<Menuitems={menuList}mode="inline"theme="dark"onClick={goNav}></Menu>

3、动态添加路由表

1、安装和配置RTX

在终端执行

yarn add redux
yarn add react-redux
yarn add @reduxjs/toolkit

在src目录下创建store文件夹,目录结构如下

src|-store|-moudles|-xx.tsx|-yy.tsx|-index
2、创建slice模块

在src/store/reducers目录下创建routeReducer.tsx

import {createSlice,PayloadAction,Dispatch} from '@reduxjs/toolkit'
import {RouteObject} from 'react-router-dom'
import api from '@/api'
import {withLoadable} from '@/utils/loadable'
interface IAuthMenu{rows:Array<any>
}
const initialState:IAuthMenu={rows:[]
}
export const routesSlice=createSlice({name:'getAuthMenu',initialState,reducers:{setAuthRoutes(state,{payload}:PayloadAction<any[]>){state.rows=payload}}
})
export const getAuthRoutesAsync=(routes:any)=>{return async(dispath:Dispatch)=>{console.log('----网络请求-----------');let result=await api.users.getAuthMenus()console.log('aaaa',result.data.data)result.data.data.forEach((item:RouteObject)=>{if(item.children){item.children.forEach((subItem:RouteObject)=>{console.log('ss',subItem)const Module=withLoadable(()=>import(`@/views${subItem.path}`))routes[1].children.push({path:subItem.path,element:<Module/>})})}})dispath(setAuthRoutes(routes))}
}
export const {setAuthRoutes}=routesSlice.actions
export default routesSlice.reducer
3、创建store对象
import {configureStore} from '@reduxjs/toolkit'import menuReducer from './reducers/menus'
const store=configureStore({reducer:{menuReducer}
})
export default store
// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState>
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch
4、创建hooks文件
​
在src/store目录下新建hooks文件import { useDispatch, useSelector } from 'react-redux'
import type { TypedUseSelectorHook } from 'react-redux'
import type { RootState, AppDispatch } from './index'// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch: () => AppDispatch = useDispatch
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
Usage With TypeScript | Redux 中文官网​
5、全局注册store
import ReactDOM from 'react-dom/client';
import App from '@/App'
import {BrowserRouter} from 'react-router-dom'
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement
);
root.render(<BrowserRouter><App /></BrowserRouter>
);
6、在组件中使用
import { Outlet, NavLink } from 'react-router-dom'
import '@/assets/css/home.scss'
import { Layout,Menu } from 'antd'
import React,{ useEffect, useState } from 'react'
import {WindowsOutlined,TrademarkCircleOutlined,UserOutlined} from '@ant-design/icons'
//导入api
import api from '@/api'
//导入接口
import IMenuData from '@/types/IMenuData'
import IMenu from '@/types/IMenu'
import IMenuFun from '@/types/IMenuFun'
//导入图标
import * as icons from '@ant-design/icons'
//导入useSelector和useDispatch
// import {useSelector,useDispatch} from 'react-redux'
//使用ts的话,hooks使用的是useAppSelector来代替useSelector,使用useAppDispatch来替换useDispatch
import {useAppSelector,useAppDispatch} from '@/store/hooks'
//导入通知对象
import {getRoutesAsync} from '@/store/modules/routesReducer'
//导入routes
import routes from '@/router'import {useNavigate} from 'react-router-dom'const { Header, Sider, Content, Footer } = Layout
export default () => {const[menuList,setMenuList]=useState<Array<any>>([])useEffect(()=>{getAuthMenus()},[])const dispatch=useAppDispatch()const nav=useNavigate()/*** 通过token向后端服务端获取权限数据*/const getAuthMenus=async()=>{const result=await api.users.getAuthMenus()//进行转换const list:Array<IMenu>=transformDataToMenu(result.data.data)setMenuList(list)//向状态机发送通知操作路由表,关键代码dispatch(getRoutesAsync(routes))}//代码略const transformDataToMenu:IMenuFun=(list:Array<IMenuData>)=>{}//进行路由跳转的方法const go=(values:any)=>{nav(values.key)}return (<Layout><Header style={{ color: '#fff' }}>蜗牛BOSS系统</Header><Layout style={{ height: '750px' }}><Sider><MenuonClick={go}items={menuList}theme="dark"mode="inline"></Menu></Sider><Content><Outlet></Outlet></Content></Layout><Footer>&copy;版权前端10期班所有</Footer></Layout>)
}
7、App.tsx
import {useRoutes} from 'react-router-dom'
import routes from '@/router'
import {useAppSelector} from '@/store/hooks'
import {useEffect,useState} from 'react'
export default ()=>{const rows=useAppSelector((state)=>{return state.routesReducer.rows})const[rout,setRout]=useState(routes)useEffect(()=>{console.log('********')console.log('rows',rows)setRout(rows)},[rows])return (<>{useRoutes(rows.length==0?routes:rout)}</>)
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/57275.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

详解过滤器Filter和拦截器Interceptor的区别和联系

目录 前言 区别 联系 前言 过滤器(Filter)和拦截器(Interceptor)都是用于在Web应用程序中处理请求和响应的组件&#xff0c;但它们在实现方式和功能上有一些区别。 区别 1. 实现方式&#xff1a; - 过滤器是基于Servlet规范的组件&#xff0c;通过实现javax.servlet.Filt…

SpringBoot初级开发--加入Log4j进行日志管理打印(6)

日志记录在整个java工程开发中占着很重要的比重&#xff0c;因为很多问题的排查需要通过日志分析才能确认。在SpringBoot中我用得最多的就是log4j这个日志框架。接下来我们具体配置log4j. log4j定义了8个级别的log&#xff08;除去OFF和ALL&#xff0c;可以说分为6个级别&#…

在云原生时代,构建高效的大数据存储与分析平台

文章目录 1. **选择适当的数据存储技术&#xff1a;**2. **采用分布式架构&#xff1a;**3. **数据分区和索引&#xff1a;**4. **采用列式存储&#xff1a;**5. **数据压缩和编码&#xff1a;**6. **使用缓存技术&#xff1a;**7. **数据分片和复制&#xff1a;**8. **自动化运…

webpack5(一)

什么是webpack webpack是一个静态资源打包工具&#xff0c;它会以一个或者多个文件作为打包的入口&#xff0c;将整个项目的所有文件编译组合成一个或多个文件输出出去。输出的文件就是编译好的文件&#xff0c;可以在浏览器端运行。一般将 webpack 输出的文件称为 bandle 。 …

做平面设计一般电脑可以吗 优漫动游

平面设计常用的软件如下&#xff1a;Photoshop、AutoCAD、AI等。其中对电脑配置要求高的是AutoCAD&#xff0c;可运行AutoCAD的软件均可运行如上软件。 做平面设计一般电脑可以吗 AutoCAD64位版配置要求&#xff1a;AMDAthlon64位处理器、支持SSE2技术的AMDOpteron处理器、…

将Spring boot 项目部署到tomcat服务艰难

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z X Y Z

芯科科技推出专为Amazon Sidewalk优化的全新片上系统和开发工具,加速Sidewalk网络采用

芯科科技为Sidewalk开发提供专家级支持 中国&#xff0c;北京 - 2023年8月22日 – 致力于以安全、智能无线连接技术&#xff0c;建立更互联世界的全球领导厂商Silicon Labs&#xff08;亦称“芯科科技”&#xff0c;NASDAQ&#xff1a;SLAB&#xff09;今日在其一年一度的第四…

Flutter 逆向安全

前言&#xff1a; 前几天在 "学习" 一个项目&#xff0c; 发现是用 Flutter 开发的。之前研究过 flutter 的逆向&#xff0c;早期 Flutter 有工具可以通过快照进行反编译&#xff1a;《对照表如下》 新的版本开发者没有维护了。 目前没有很好的工具 可以对 Flutter 进…

编译tiny4412 Linux 内核

工作环境 Ubuntu 22 交叉编译器 4.5.1 解压Linux内核源码&#xff0c;进入目录 将官方配置完好的defconfig文件作为配置文件 cp tiny4412_linux_defconfig .config由于内核版本较低&#xff0c;需要下载低版本的gcc&#xff0c;选择下载gcc-9与g9 sudo apt install gcc-9 g-…

软件工程(十八) 行为型设计模式(四)

1、状态模式 简要说明 允许一个对象在其内部改变时改变它的行为 速记关键字 状态变成类 类图如下 状态模式主要用来解决对象在多种状态转换时,需要对外输出不同的行为的问题。比如订单从待付款到待收货的咋黄台发生变化,执行的逻辑是不一样的。 所以我们将状态抽象为一…

17.CSS发光按钮悬停特效

效果 源码 <!DOCTYPE html> <html> <head><title>CSS Modern Button</title><link rel="stylesheet" type="text/css" href="style.css"> </head> <body><a href="#" style=&quo…

手机无人直播软件有哪些,又有哪些优势?

如今&#xff0c;随着智能手机的普及和移动互联网的发展&#xff0c;手机无人直播成为了一个炙手可热的领域。手机无人直播软件为用户提供了便捷、灵活的直播方式&#xff0c;让更多商家人能够实现自己的直播带货的梦想。接下来&#xff0c;我们将探讨手机无人直播软件有哪些&a…

Excel通用表头及单元格合并

要在Java中实现XLS文件中的通用表头合并和单元格合并&#xff0c;您可以使用Apache POI库。下面是一个示例代码&#xff0c;展示了如何实现这两个功能&#xff1a; import org.apache.poi.hssf.usermodel.*; import org.apache.poi.ss.usermodel.*;import java.io.FileOutputS…

React 全栈体系(三)

第二章 React面向组件编程 四、组件三大核心属性3: refs与事件处理 1. 效果 需求: 自定义组件, 功能说明如下: 点击按钮, 提示第一个输入框中的值当第2个输入框失去焦点时, 提示这个输入框中的值 2. 理解 组件内的标签可以定义ref属性来标识自己 3. 编码 3.1 字符串形式…

图文并茂:Python Tkinter从入门到高级实战全解析

目录 介绍什么是Tkinter&#xff1f;准备工作第一个Tkinter程序界面布局事件处理补充知识点 文本输入框复选框和单选框列表框弹出对话框 综合案例&#xff1a;待办事项列表总结 介绍 欢迎来到本篇文章&#xff0c;我们将带您深入了解如何在Python中使用Tkinter库来创建图形用…

电脑不安装软件,怎么将手机文件传输到电脑?

很多人都知道&#xff0c;AirDroid有网页版&#xff08;web.airdroid.com&#xff09;。 想要文件传输&#xff0c;却不想在电脑安装软件时&#xff0c;AirDroid的网页版其实也可以传输文件。 然而&#xff0c;要将文件从手机传输文件到网页端所在的电脑时&#xff0c;如果按…

服务器安全-修改默认ssh端口

防火墙先打开指定端口,要不修改后连不上(端口需要在65535之内) firewall-cmd --list-ports firewall-cmd --add-port54111/tcp --permanent firewall-cmd --reload-------------------- 先让两个端口同时存在,等配置成功后关闭22端口 vim /etc/ssh/sshd_config重启sshd service…

关于亚马逊云科技云技能孵化营学习心得

1、活动介绍 本活动主要是面向想要全面了解亚马逊云科技 (Amazon Web Services) 云的个人&#xff0c;而不受特定技术角色的限制。内容包括亚马逊云科技云概念、亚马逊云科技服务、安全性、架构、定价和支持等等&#xff0c;此外还可以参加亚马逊的认证考试。 2、学习过程 该…

复数的四则运算(java版)

复数的四则运算&#xff08;java版&#xff09; 目录 复数的四则运算&#xff08;java版&#xff09;介绍复数的四则运算实现思路代码1、封装复数类2、测试复数类3、代码测试结果 介绍 复数&#xff0c;为实数的延伸&#xff0c;它使任一多项式方程都有根。复数当中有个“虚数单…

【Go 基础篇】探索Go语言中Map的神奇操作

嗨&#xff0c;Go语言的学习者们&#xff01;在编程世界中&#xff0c;Map是一个强大而又有趣的工具&#xff0c;它可以帮助我们高效地存储和操作键值对数据。Map就像是一本字典&#xff0c;可以让我们根据关键字&#xff08;键&#xff09;快速找到对应的信息&#xff08;值&a…