Typescript+React

37 阅读3分钟

一、环境搭建

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'
  })
}