react保姆级搭建新项目

简介: 此文主要以ts+vite+router6+antd 快速搭建一个react项目,适用于初学者,用于学习交流

一、项目搭建
采用vite方式 ,根据选择 react-ts
pnpm create vite
1.1 修改初始结构,删除多余文件

1.2 修改vite.config配置文件 配置别名
vite.config:

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import path from 'path';

export default defineConfig({
plugins: [react()],
resolve: {
alias:{
"@":path.resolve(__dirname,'./src')//配置@别名
}
},
})
💡 Tips:为了ts不报错需要配置 tsconfig.json
tsconfig.json:

具体tsconfig配置参数详解
{
"compilerOptions": {
"target": "ESNext",// 指定ECMAScript目标版本
"useDefineForClassFields": true,//此标志用作迁移到即将推出的类字段标准版本的一部分
"lib": ["DOM", "DOM.Iterable", "ESNext"],//用于指定需要包含的模块,只有在这里列出的模块的声明文件才会被加载
"allowJs": false, // 允许 ts 编译器编译 js 文件
"skipLibCheck": true, // 跳过声明文件的类型检查
"esModuleInterop": false,// es 模块互操作,屏蔽 ESModule和CommonJS之间的差异
"allowSyntheticDefaultImports": true, // 允许通过import x from 'y' 即使模块没有显式指定 default 导出
"strict": true,//true => 同时开启 alwaysStrict, noImplicitAny, noImplicitThis 和 strictNullChecks
"forceConsistentCasingInFileNames": true, // 对文件名称强制区分大小写
"module": "ESNext",// 指定生成哪个模块系统代码
"moduleResolution": "Node",// 模块解析(查找)策略
"resolveJsonModule": true,// 防止 ts文件中引入json文件,会报如下红色波浪线
"isolatedModules": true,// 是否将没有 import/export 的文件视为旧(全局而非模块化)脚本文件。
"noEmit": true, // 编译时不生成任何文件(只进行类型检查)
"jsx": "react-jsx", // 指定将 JSX 编译成什么形式
"baseUrl": "./src",//配置paths前先配置baseUrl
"paths": {
"@/": [""], // 模块名到基于 baseUrl的路径映射的列表
},
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}

❗❗❗❗如找不到path或找不到__dirname等

💡 Tips:如图报node自带模块的错误,需要安装 @types/node
pnpm add @types/node --save-dev

二、路由 react-router-dom@6配置

  1. pnpm add react-router-dom@6 --save-dev
  2. 在根文件main.tsx里面 修改 在app外层用BrowserRouter包裹
    import ReactDOM from "react-dom/client";
    import App from "./App";
    import { BrowserRouter } from "react-router-dom";

ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(



);

3.在router文件夹下创建index.tsx

import { Routes, Route } from "react-router-dom";
import {lazy} from "react";

const Home = lazy(() => import("@/pages/home"))
const Login = lazy(() => import("@/pages/login"))

function RootRoute() :JSX.Element{
return (
<>

} />
} />

</>
);
}
export default RootRoute
💡 Tips:path为路径,element为引入的路由文件。
4.在app.tsx 引入router文件即可

三、引入antd
ant-design 官网镜像地址:
http://ant-design.gitee.io/index-cn
ant-design-pro镜像地址:
http://ant-design-pro.gitee.io/index-cn
antd-mobile镜像地址:
https://antd-mobile.gitee.io/index-cn
ant-design的正常地址https://ant.design/index-cn
1.下载
pnpm add antd
2.引入antd样式
💡 Tips:在入口文件 引入的css文件里如app.css(注意在最上方)
@import'antd/dist/antd.css';
3使用
💡 Tips:根据antd文档 在使用的地方子回家引入 如:
import { Button } from 'antd';
四、封装axios
1.下载
pnpm add axios -S
2.构建项目目录 如图 配置正式测试环境地址
2.1 新增http文件夹 在其中生产如下文件

2.2 新建.env 区分环境

根据实际情况配置

修改package.json 启动命令
"scripts": {
"dev": "vite serve --mode development",
"build:pro": "tsc && vite build --mode production",
},
3.编写index文件
具体逻辑可以新增
import axios, { AxiosInstance, AxiosError, AxiosRequestConfig, AxiosResponse } from "axios";
import { AxiosCanceler } from "./helper/axiosCancel";
import { checkStatus } from "./helper/checkStatus";
import { message } from 'antd'

enum ResultEnum {
SUCCESS = 200,
ERROR = 500,
OVERDUE = 10001,
TIMEOUT = 6000,
TYPE = "success"
}

interface Result {
code: number;
message: string;
}

// * 请求响应参数(包含data)
interface ResultData extends Result {
data?: T;
}

const axiosCanceler = new AxiosCanceler();

const config = {
// 默认地址请求地址,可在 .env 开头文件中修改
baseURL: import.meta.env.VITE_APP_BASE_API as string,
// 设置超时时间(10s)
timeout: ResultEnum.TIMEOUT as number,
// 跨域时候允许携带凭证
withCredentials: true
};

class RequestHttp {
service: AxiosInstance;
constructor(config: AxiosRequestConfig) {
// 实例化axios
this.service = axios.create(config);

  /**
  * @description 请求拦截器
  */
  this.service.interceptors.request.use(
    (config: AxiosRequestConfig) => {
      axiosCanceler.addPending(config);
      // * 需要添加的token 自行设置
      const token: string|null = '';
      return { ...config, headers: { "token": token } };
    }, 
    (error: AxiosError) => {
      return Promise.reject(error);
    }
  );

  /**
  * @description 响应拦截器
  */
  this.service.interceptors.response.use(
    (response: AxiosResponse) => {
      const { data, config } = response;
      // * 在请求结束后,移除本次请求
      axiosCanceler.removePending(config);
      // * 登陆失效操作
      if (data.code == ResultEnum.OVERDUE) {
        message.error(data.message);
        return Promise.reject(data);
      }
      // * 全局错误信息拦截(防止下载文件得时候返回数据流,没有code,直接报错)
      if (data.code && data.code !== ResultEnum.SUCCESS) {
        return Promise.reject(data);
      }
      // * 成功请求
      return data;
    },
    async (error: AxiosError) => {
      const { response } = error;
      // 根据响应的错误状态码,做不同的处理
      if (response) return checkStatus(response.status);
      // 服务器结果都没有返回(可能服务器错误可能客户端断网),断网处理:可以跳转到断网页面
      if (!window.navigator.onLine) return 
      return Promise.reject(error);
    }
  );
}

// * 常用请求方法封装
get<T>(url: string, params?: any, _object = {}): Promise<ResultData<T>> {
  return this.service.get(url, { params, ..._object });

}
post(url: string, params?: object, _object = {}): Promise> {
return this.service.post(url, params, _object);
}
put(url: string, params?: object, _object = {}): Promise> {
return this.service.put(url, params, _object);
}
delete(url: string, params?: any, _object = {}): Promise> {
return this.service.delete(url, { params, ..._object });
}
}

export default new RequestHttp(config);

4.checkStatus.ts
import { message } from 'antd'
/**

  • @description: 校验网络请求状态码
  • @param {Number} status
  • @return void
    */
    export const checkStatus = (status: number): void => {
    switch (status) {
     case 400:
         message.error("请求失败!请您稍后重试");
         break;
     case 401:
         message.error("登录失效!请您重新登录");
         break;
     case 403:
         message.error("当前账号无权限访问!");
         break;
     case 404:
         message.error("你所访问的资源不存在!");
         break;
     case 405:
         message.error("请求方式错误!请您稍后重试");
         break;
     case 408:
         message.error("请求超时!请您稍后重试");
         break;
     case 500:
         message.error("服务异常!");
         break;
     case 502:
         message.error("网关错误!");
         break;
     case 503:
         message.error("服务不可用!");
         break;
     case 504:
         message.error("网关超时!");
         break;
     default:
         message.error("请求失败!");
    
    }
    };

5.axiosCancel.ts
💡 Tips:先下载qs模块
pnpm add qs
如确认下载qs模块后 遇见qs报错 则需要 下载@types/qs
pnpm add @types/qs -D
import axios, { AxiosRequestConfig, Canceler } from "axios";
import qs from "qs";

const isFunction(val: unknown) {
return toString.call(val) === [object Function];
}
// * 声明一个 Map 用于存储每个请求的标识 和 取消函数
let pendingMap = new Map();

// * 序列化参数
export const getPendingUrl = (config: AxiosRequestConfig) =>
[config.method, config.url, qs.stringify(config.data), qs.stringify(config.params)].join("&");

export class AxiosCanceler {
/**

 * @description: 添加请求
 * @param {Object} config
 * @return void
 */
addPending(config: AxiosRequestConfig) {
    // * 在请求开始前,对之前的请求做检查取消操作
    this.removePending(config);
    const url = getPendingUrl(config);
    config.cancelToken =
        config.cancelToken ||
        new axios.CancelToken(cancel => {
            if (!pendingMap.has(url)) {
                // 如果 pending 中不存在当前请求,则添加进去
                pendingMap.set(url, cancel);
            }
        });
}

/**
 * @description: 移除请求
 * @param {Object} config
 */
removePending(config: AxiosRequestConfig) {
    const url = getPendingUrl(config);

    if (pendingMap.has(url)) {
        // 如果在 pending 中存在当前请求标识,需要取消当前请求,并且移除
        const cancel = pendingMap.get(url);
        cancel && cancel();
        pendingMap.delete(url);
    }
}

/**
 * @description: 清空所有pending
 */
removeAllPending() {
    pendingMap.forEach(cancel => {
        cancel && isFunction(cancel) && cancel();
    });
    pendingMap.clear();
}

/**
 * @description: 重置
 */
reset(): void {
    pendingMap = new Map<string, Canceler>();
}

}

五、vscode配置
5.1 ts模块的react代码片段

{
"全局React-ts函数组件模板": {
"scope": "javascript,typescript,typescriptreact",
"prefix": "rfc-ts", //快捷命令 可以自己定义
"body": [
"import React,{FC,ReactElement} from 'react';",
"",
"const ${TM_FILENAME_BASE}: FC = ():ReactElement => {",
" return

;",
"};",
"",
"export default ${TM_FILENAME_BASE};",
""
],
"description": "React函数组件默认模版"
}
}

5.2 .es和.prettierrc

💡 Tips:先下载依赖
pnpm add eslint eslint-config-prettier eslint-plugin-prettier @typescript-eslint/eslint-plugin @typescript-eslint/parser prettier
根目录建立.eslintrc.cjs、.eslintignore、.prettierrc.cjs、.prettierignore

module.exports = {
parser: '@typescript-eslint/parser',
extends:[
'prettier/@typescript-eslint',
'plugin:prettier/recommended'
],
settings: {
"react": {
"pragma": "React",
"version": "detect"
}
},
parserOptions: {
"ecmaVersion": 2019,
"sourceType": 'module',
"ecmaFeatures":{
jsx:true
}
},
env:{
browser: true,
node: true,
}
}

module.exports = {
// 一行最多 100 字符
printWidth: 100,
// 使用 4 个空格缩进
tabWidth: 4,
// 不使用缩进符,而使用空格
useTabs: false,
// 行尾需要有分号
semi: true,
// 使用单引号
singleQuote: true,
// 对象的 key 仅在必要时用引号
quoteProps: 'as-needed',
// jsx 不使用单引号,而使用双引号

jsxSingleQuote: false,
// 末尾不需要逗号
trailingComma: 'none',
// 大括号内的首尾需要空格
bracketSpacing: true,
// jsx 标签的反尖括号需要换行
jsxBracketSameLine: false,
// 箭头函数,只有一个参数的时候,也需要括号
arrowParens: 'always',
// 每个文件格式化的范围是文件的全部内容
rangeStart: 0,
rangeEnd: Infinity,
// 不需要写文件开头的 @prettier
requirePragma: false,
// 不需要自动在文件开头插入 @prettier
insertPragma: false,
// 使用默认的折行标准
proseWrap: 'preserve',
// 根据显示样式决定 html 要不要折行
htmlWhitespaceSensitivity: 'css',
// 换行符使用 lf
endOfLine: 'lf'

};

node_modules/
dist/
index.html
//定义忽略文件
*/node_modules/
build
//定义忽略文件

相关文章
|
13天前
|
前端开发 JavaScript 测试技术
从零开始搭建react+typescript+antd+redux+less+vw自适应项目
从零开始搭建react+typescript+antd+redux+less+vw自适应项目
68 0
|
13天前
|
前端开发 API 数据安全/隐私保护
【第45期】一文解决React项目的权限管理
【第45期】一文解决React项目的权限管理
131 0
|
13天前
|
Web App开发 资源调度 JavaScript
竟然可以在一个项目中混用 Vue 和 React?
竟然可以在一个项目中混用 Vue 和 React?
189 0
|
13天前
|
前端开发 API
react如何进行项目配置代理
react如何进行项目配置代理
68 0
|
13天前
|
运维 JavaScript 前端开发
发现了一款宝藏学习项目,包含了Web全栈的知识体系,JS、Vue、React知识就靠它了!
发现了一款宝藏学习项目,包含了Web全栈的知识体系,JS、Vue、React知识就靠它了!
|
13天前
|
移动开发 JavaScript 前端开发
vue/react项目刷新页面出现404的原因以及解决办法
vue/react项目刷新页面出现404的原因以及解决办法
250 0
|
13天前
|
前端开发 JavaScript API
Github 上 8 个很棒的 React 项目
Github 上 8 个很棒的 React 项目
337 0
|
13天前
|
前端开发 开发工具 git
React项目包结构的作用
React项目包结构的作用
64 0
|
13天前
|
前端开发
React 中 react-i18next 切换语言( 项目国际化 )
React 中 react-i18next 切换语言( 项目国际化 )
181 0
|
13天前
|
存储 资源调度 前端开发
【React | 完整项目创建流程】能看到这么详细的React配置流程,就偷着乐吧!
【React | 完整项目创建流程】能看到这么详细的React配置流程,就偷着乐吧!