一、环境搭建
npx create-react-app my-app --template typescript
cd my-app
npm start
npm i @types/react -s
npm i @types/react-dom -s
二、使用Typescript来定义组件的类型(在Typescript环境下定义组件的格式)
import React, { useState,memo } from 'react';
import type { FC, ReactNode } from 'react'
//先利用接口来定义一个结构
interface IProps {
children?:ReactNode
}
//再利用 const 组件名:React.FC<IProps>=(props)=>{} export default memo(组件名)
const MyComponent: React.FC<Props> = ({ initialCount }) => {
const [count, setCount] = useState(initialCount);
const handleIncrement = () => {
setCount(count + 1);
};
return (
<div>
<p>Count: {count}</p>
<button onClick={handleIncrement}>Increment</button>
</div>
);
};
export default memo(MyComponent);
三、路由管理
npm install react-router-dom
import React, { lazy } from 'react'
import { Navigate } from 'react-router-dom'
import type { RouteObject } from 'react-router-dom'
const 组件名 =lazy(()=>import ('路径'))
const routes:RouteObject[]=[
{
path:'/',
//表示当浏览器路径匹配到'/'时,页面自动跳转到element中的路由组件中显示。
element:<Navigate to="/discover" />
},
{
//表示当浏览器中的地址路径为/discover时,展示Discover组件。
path:'/discover',
element:<Discover/>,
//children表示当前路由组件下的二级路由组件
children:[
{
path:'/discover',
//表示如果当前的浏览器地址路径为/discover时,默认自动跳转到recommend组件显示。
element:<Navigate to="/discover/recommend" />
},
{
path:'/discover/recommend',
element:<Recommend/>
}
...
]
}
]
export default routes
利用useRoutes(routes)来根据当前浏览器中的路由地址去匹配规定好的路由规则中的路由页面显示。
在APP.tsx中展示页面内容
import { useRoutes } from 'react-router-dom'
<Suspense fallback="">
<div className="main">{useRoutes(routes)}</div>
</Suspense>
四、redux配置
npm install @reduxjs/toolkit react-redux
在src/store/index.tsx中配置:
type GetStateFnType=typeof store.getState
export type IRootState=ReturnType<GetStateFnType>
type DispatchType=typeof store.dispatch
export const useAppSelector :TypedUseSelectorHook<IRootState> =useSelector
export const useAppDispatch :()=>DispatchType =useDispatch
export const shallowEqualApp=shallowEqual
之后便利用 useAppSelctor来获取redux中存储的数据,利用useAppDispatch来修改redux中存储的数据
import {createSlice,PayloadAction} from '@reduxjs/toolkit'
interface IState {
//这里定义state中的数据的类型
}
const initialState:IState ={
数据名:数据值
}
const 仓库名=createSlice({
name:'xxx',
initialState,
reducers:{
同步方法名(state,{payload}:PayloadAction<参数的数据类型>){}
}
})
五、二次封装axios
service/request/config.ts:
const BASE_URL = 'http://codercba.com:9002/'
const TIME_OUT = 10000
console.log(process.env.REACT_APP_NAME)
console.log(process.env.REACT_APP_AGE)
export { BASE_URL, TIME_OUT }
service/request/type.ts:
import type { AxiosRequestConfig, AxiosResponse } from 'axios'
export interface HYRequestInterceptors<T = AxiosResponse> {
requestInterceptor?: (config: AxiosRequestConfig) => AxiosRequestConfig
requestInterceptorCatch?: (error: any) => any
responseInterceptor?: (res: T) => T
responseInterceptorCatch?: (error: any) => any
}
export interface HYRequestConfig<T = AxiosResponse> extends AxiosRequestConfig {
interceptors?: HYRequestInterceptors<T>
showLoading?: boolean
}
service/request/index.ts:
import axios from 'axios'
import type { AxiosInstance } from 'axios'
import type { HYRequestInterceptors, HYRequestConfig } from './type'
const DEAFULT_LOADING = true
class HYRequest {
instance: AxiosInstance
interceptors?: HYRequestInterceptors
showLoading: boolean
constructor(config: HYRequestConfig) {
// 创建axios实例
this.instance = axios.create(config)
// 保存基本信息
this.showLoading = config.showLoading ?? DEAFULT_LOADING
this.interceptors = config.interceptors
// 使用拦截器
// 1.从config中取出的拦截器是对应的实例的拦截器
this.instance.interceptors.request.use(
this.interceptors?.requestInterceptor,
this.interceptors?.requestInterceptorCatch
)
this.instance.interceptors.response.use(
this.interceptors?.responseInterceptor,
this.interceptors?.responseInterceptorCatch
)
// 2.添加所有的实例都有的拦截器
this.instance.interceptors.request.use(
(config) => {
return config
},
(err) => {
return err
}
)
this.instance.interceptors.response.use(
(res) => {
const data = res.data
if (data.returnCode === '-1001') {
console.log('请求失败~, 错误信息')
} else {
return data
}
},
(err) => {
// 例子: 判断不同的HttpErrorCode显示不同的错误信息
if (err.response.status === 404) {
console.log('404的错误~')
}
return err
}
)
}
request<T = any>(config: HYRequestConfig<T>): Promise<T> {
return new Promise((resolve, reject) => {
// 1.单个请求对请求config的处理
if (config.interceptors?.requestInterceptor) {
config = config.interceptors.requestInterceptor(config)
}
// 2.判断是否需要显示loading
if (config.showLoading === false) {
this.showLoading = config.showLoading
}
this.instance
.request<any, T>(config)
.then((res) => {
// 1.单个请求对数据的处理
if (config.interceptors?.responseInterceptor) {
res = config.interceptors.responseInterceptor(res)
}
// 2.将showLoading设置true, 这样不会影响下一个请求
this.showLoading = DEAFULT_LOADING
// 3.将结果resolve返回出去
resolve(res)
})
.catch((err) => {
// 将showLoading设置true, 这样不会影响下一个请求
this.showLoading = DEAFULT_LOADING
reject(err)
return err
})
})
}
get<T = any>(config: HYRequestConfig<T>): Promise<T> {
return this.request<T>({ ...config, method: 'GET' })
}
post<T = any>(config: HYRequestConfig<T>): Promise<T> {
return this.request<T>({ ...config, method: 'POST' })
}
delete<T = any>(config: HYRequestConfig<T>): Promise<T> {
return this.request<T>({ ...config, method: 'DELETE' })
}
patch<T = any>(config: HYRequestConfig<T>): Promise<T> {
return this.request<T>({ ...config, method: 'PATCH' })
}
}
export default HYRequest
然后二次封装完axios后,可以开始封装接口方法: eg:
可以在每一个路由组件所属的文件夹下新建service文件夹,用于存放封装好的接口方法
recommend/service/recommend.ts
import hyRequest from '@/service'
export function getTopBanner() {
return hyRequest.get({
url: '/banner'
})
}