当前位置: 首页 > news >正文

React 与 TypeScript 极客园移动端

一、基础环境创建

npm create vite@latest react-ts-pro -- --template react-ts
npm i
npm run dev

二、useState

1. 自动推导

通常 React 会根据传入 useState 的默认值来自动推导类型,不需要显式标注类型

const [value, toggle] = useState(false)

说明:

(1)value:类型为 boolean

(2)toggle: 参数类型为 boolean

// react + ts
// 根据初始值自动推断
// 场景:明确的初始值
import { useState } from 'react'function App() {const [value, toggle] = useState(false)const [list, setList] = useState([1, 2, 3])const changeValue = () => {toggle(true)}const changeList = () => {setList([4])}return <>this is app {list}</>
}export default App

2. 泛型参数

useState 本身是一个泛型函数,可以传入具体的自定义类型

type User = {name: stringage: number
}const [user, setUser] = useState<User>()

说明:

(1)限制 useState 函数参数的初始值必须满足类型为:User | () => User

(2)限制 useState 函数的参数必须满足类型为:User | () => User | undefined

(3)user 状态数据具备 User 类型相关的类型提示

// react + ts
import { useState } from 'react'type User = {name: stringage: number
}function App() {// 1. 限制初始值的类型// const [user, setUser] = useState<User>({//   name: 'jack',//   age: 18,// })// const [user, setUser] = useState<User>(() => {//   return {//     name: 'jack',//     age: 18,//   }// })const [user, setUser] = useState<User>({name: 'jack',age: 18,})const changeUser = () => {setUser(() => ({name: 'john',age: 28,}))}return <>this is app {user.name}</>
}export default App

3. 初始值为 null

当我们不知道状态的初始值是什么,将 useState 的初始值为 null 是一个常见的做法,可以通过具体类型联合 null 来做显式注解

type User = {name: stringage: number
}const [user, setUser] = useState<User | null>(null)

 说明:

(1)限制 useState 函数参数的初始值可以是 User | null

(2)限制 setUser 函数的参数类型可以是 User | null

// react + ts
import { useState } from 'react'type User = {name: stringage: number
}function App() {const [user, setUser] = useState<User | null>(null)const changeUser = () => {setUser(null)setUser({name: 'jack',age: 18,})}// 为了类型安全  可选链做类型守卫// 只有user不为null(不为空值)的时候才进行点运算return <>this is app {user?.age}</>
}export default App

三、Props 与 TypeScript

1. 基础使用

为组件 prop 添加类型,本质是给函数的参数做类型注解,可以使用 type 对象类型或者 interface 接口来做注解

type Props = {className: string
}function Button(props: Props){const { className } = propsreturn <button className={className}>click me</button>
}

说明:Button 组件只能传入名称为 className 的 prop 参数,类型为 string,且为必填

// props + ts// type Props = {
//   className: string
// }interface Props {className: stringtitle?: string
}function Button(props: Props) {const { className } = propsreturn <button className={className}>click me </button>
}function App() {return (<><Button className="test" title="this is title" /></>)
}export default App

2. 特殊的 children 属性

children 是一个比较特殊的 prop,支持多种不同类型数据的传入,需要通过一个内置的 ReactNode 类型来做注释

type Props = {className: stringchildren: React.ReactNode
}function Button(props: Props){const { className, children } = propsreturn <button className={className}>{children}</button>
}

说明:注解之后,children 可以是多种类型,包括:React.ReactElement、string、number、React.ReactFragment、React.ReactPortal、boolean、null、undefined

// props + ts
type Props = {className: stringchildren: React.ReactNode
}function Button(props: Props) {const { className, children } = propsreturn <button className={className}>{children} </button>
}function App() {return (<><Button className="test">click me!</Button><Button className="test"><span>this is span</span></Button></>)
}export default App

3. 为事件 prop 添加类型

组件经常执行类型为函数的 prop 实现子传父,这类 prop 重点在于函数参数类型的注解

说明:

(1)在组件内部调用时需要遵守类型的约束,参数传递需要满足要求

(2)绑定 prop 时如果绑定内联函数直接可以推断出参数类型,否则需要单独注解匹配的参数类型

// props + ts
type Props = {onGetMsg?: (msg: string) => void
}function Son(props: Props) {const { onGetMsg } = propsconst clickHandler = () => {onGetMsg?.('this is msg')}return <button onClick={clickHandler}>sendMsg</button>
}function App() {const getMsgHandler = (msg: string) => {console.log(msg)}return (<><Son onGetMsg={(msg) => console.log(msg)} /><Son onGetMsg={getMsgHandler} /></>)
}export default App

四、useRef 与 TypeScript

1. 获取 dom

获取 dom 的场景,可以直接把要获取的 dom 元素的类型当成泛型参数传递给 useRef, 可以推导出 .current 属性的类型

function App(){const domRef = useRef<HTMLInputElement>(null)useEffect(() => {domRef.current?.focus()}, [])return (<><input ref={domRef}/></>)
}

2. 引用稳定的存储器

把 useRef 当成引用稳定的存储器使用的场景可以通过泛型传入联合类型来做,比如定时器的场景:

function App(){const timerRef = useRef<number | undefined>(undefined)useEffect(() => {timerRef.current = setInterval(() => {console.log('1')}, 1000)return () => clearInterval(timerRef.current)}, [])return <>this is div</>
} 
// useRef + ts
import { useEffect, useRef } from 'react'// 1. 获取dom
// 2. 稳定引用的存储器(定时器管理)function App() {const domRef = useRef<HTMLInputElement>(null)const timerId = useRef<number | undefined>(undefined)useEffect(() => {// 可选链  前面不为空值(null / undefined)执行点运算// 类型守卫 防止出现空值点运算错误domRef.current?.focus()timerId.current = setInterval(() => {console.log('123')}, 1000)return () => clearInterval(timerId.current)}, [])return (<><input ref={domRef} /></>)
}export default App

五、极客园移动端

1. 项目环境创建

基于 vite 创建开发环境

vite 是一个框架无关的前端工具链,可以快速的生成一个 React + TS 的开发环境,并且可以提供快速的开发体验

npm create vite@latest react-jike-mobile -- --template react-ts

 说明:
(1)npm create vite@latest 固定写法 (使用最新版本 vite 初始化项目)

(2)react-ts-pro 项目名称 (可以自定义)

(3)-- --template react-ts 指定项目模版位 react + ts

2. 安装 Ant Design Mobile

Ant Design Mobile 是 Ant Design 家族里专门针对移动端的组件库

看文档!

3. 配置基础路由

初始化路由

React 的路由初始化,我们采用 react-router-dom 进行配置

 

4. 配置别名路径

场景:项目中各个模块之间的互相导入导出,可以通过 @ 别名路径做路径优化,经过配置 @ 相当于 src 目录,比如:

import Detail from '../pages/Detail'import Detail from '@/pages/Detail'

步骤:

(1)让 vite 做路径解析 (真实的路径转换)

(2)让 vscode 做智能路径提示 (开发者体验)

vite.config.ts

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import path from 'path'// https://vitejs.dev/config/
export default defineConfig({plugins: [react()],resolve: {alias: {'@': path.resolve(_dirname, './src')},},})

安装 node 类型包

npm i @types/node -D

tsconfig.json

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

5. 安装 axios

场景:axios 作为最流行的请求插件,同样是类型友好的,基于 axios 做一些基础的封装

(1)安装 axios 到项目

(2)在 utils 中封装 http 模块,主要包括 接口基地址、超时时间、拦截器

(3)在 utils 中做统一导出

npm i axios

utils/http.ts

// axios的封装处理
import axios from "axios"const httpInstance = axios.create({baseURL: 'http://geek.itheima.net',timeout: 5000
})// 添加请求拦截器
httpInstance.interceptors.request.use((config) => {return config
}, (error) => {return Promise.reject(error)
})// 添加响应拦截器
httpInstance.interceptors.response.use((response) => {// 2xx 范围内的状态码都会触发该函数。// 对响应数据做点什么return response.data
}, (error) => {// 超出 2xx 范围的状态码都会触发该函数。// 对响应错误做点什么return Promise.reject(error)
})export { httpInstance }

utils/index.js

// 统一中转工具模块函数
// import { httpInstance } from '@/utils'import { httpInstance as http } from './request'export {http,
}

 

6. 封装 API 模块

场景:axios 提供了 request 泛型方法,方便我们传入类型参数推导出接口返回值的类型

 

http://www.xdnf.cn/news/585343.html

相关文章:

  • OpenCV CUDA模块图像过滤------用于创建一个最小值盒式滤波器(Minimum Box Filter)函数createBoxMinFilter()
  • Android 内存溢出(OOM)的 Kotlin 排查与优化指南
  • 博客打卡-0/1背包问题,回溯法
  • 类和对象(4)--《Hello C++ Wrold!》(6)--(C/C++)--赋值运算符重载,取地址和const取地址操作符重载
  • 嵌入式STM32学习——串口USART 2.2(串口中断接收)
  • Python字符串格式化(二): f-string的进化
  • 企业级爬虫进阶开发指南
  • 【linux知识】sftp配置免密文件推送
  • 开搞:第四个微信小程序:图上县志
  • 获取印度股票市场API
  • 关于XILINX的XDC约束文件编写
  • HarmonyOS 鸿蒙应用开发基础:EventHub,优雅解决跨组件通信难题
  • 10.IIC和BH1750
  • 基于单片机的室内采光及可燃气体泄漏报警装置设计
  • SCons构建工具使用指南及示例
  • JAVA SE — 循环与分支和输入输出
  • 有没有开源的企业网盘,是否适合企业使用?
  • 记录:express router,可以让node.js后端文件里的路由分布的更清晰
  • vim以及vi编辑器常用快捷键指令
  • 服务器操作系统调优内核参数(方便查询)
  • 复杂项目中通过使用全局变量解决问题的思维方式
  • 2025中青杯数学建模B题思路+模型+代码
  • 【TTS回顾】CosyVoice 深度解析:基于LLM的TTS模型
  • iOS 直播弹幕功能的实现
  • 前端三件套之html详解
  • DevOps体系之Jmeter
  • java面试每日一背 day2
  • MySQL错误1419(HY000)解决方案:SUPER权限缺失与二进制日志启用冲突的3种处理方式
  • 内存管理子系统学习记录
  • uniapp实现H5、APP、微信小程序播放.m3u8监控视频