当前位置: 首页 > 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 泛型方法,方便我们传入类型参数推导出接口返回值的类型

 

相关文章:

  • 旋转编码器计次 红外对射传感器计次小实验及其相关库函数详解 (江协科技)
  • 《洞察因果本质:解锁智能体大模型精准预测的底层逻辑》
  • torch.gather()和torch.sort
  • Human DiO-LDL,绿色荧光标记人源低密度脂蛋白,研究细胞内吞
  • vscode include总是报错
  • 印度语言指令驱动的无人机导航!UAV-VLN:端到端视觉语言导航助力无人机自主飞行
  • nltk-英文句子分词+词干化
  • 如何顺利地将应用程序从 Android 转移到Android
  • 微服务架构中的 RabbitMQ:异步通信与服务解耦(一)
  • 第六部分:阶段项目 5:构建 NestJS RESTful API 服务器
  • 5G 网络全场景注册方式深度解析:从信令交互到报文分析
  • Day124 | 灵神 | 二叉树 | 二叉树最小深度
  • 什么是VR展馆?VR展馆的实用价值有哪些?
  • 110kV/630mm2电缆5km的交流耐压试验兼顾110kVGIS开关用
  • jquery.table2excel方法导出
  • Cause: org.apache.ibatis.ognl.OgnlException: sqlSegment
  • 新手到资深的Java开发编码规范
  • 游戏如何应对反编译工具dnspy
  • b/s开发 1.0
  • C++ JSON解析技术详解
  • 国际业务网站有哪些/现在最好的营销方式
  • 如何建设手机端网站/广州seo快速排名
  • wordpress官网打不开/seo网络营销外包公司
  • 建网站申请/百度移动端优化
  • 惠州城市建设建筑网站/长春seo优化
  • 策划网站建设/品牌推广策划