React【Day11】

阶段重点

React和TypeScript集合使用的重点集中在 和存储数据/状态有关的Hook函数 以及 组件接口 的位置,这些地方最需要数据类型校验

使用Vite创建项目

Vite是一个框架无关的前端工具链工具,可以帮助我们快速创建一个 react+ts 的工程化环境出来,我们可以基于它做语法学习

Vite

npm create vite@latest react-typescript -- --template react-ts

安装依赖运行项目

# 安装依赖
npm i 

# 运行项目
npm run dev

保留的文件:
在这里插入图片描述

useState

简单场景

简单场景下,可以使用TS的自动推断机制,不用特殊编写类型注解,运行良好

const [val, toggle] = React.useState(false)

// `val` 会被自动推断为布尔类型
// `toggle` 方法调用时只能传入布尔类型

复杂场景

复杂数据类型,useState支持通过泛型参数指定初始参数类型以及setter函数的入参类型

type User = {
  name: string
  age: number
}
const [user, setUser] = React.useState<User>({
  name: 'jack',
  age: 18
})
// 执行setUser
setUser(newUser)
// 这里newUser对象只能是User类型

没有具体默认值

实际开发时,有些时候useState的初始值可能为null或者undefined,按照泛型的写法是不能通过类型校验的,此时可以通过完整的类型联合null或者undefined类型即可

type User = {
  name: String
  age: Number
}
const [user, setUser] = React.useState<User>(null)
// 上面会类型错误,因为null并不能分配给User类型

const [user, setUser] = React.useState<User | null>(null)
// 上面既可以在初始值设置为null,同时满足setter函数setUser的参数可以是具体的User类型

useRef

在TypeScript的环境下,useRef 函数返回一个只读 或者 可变 的引用,只读的场景常见于获取真实dom,可变的场景,常见于缓存一些数据,不跟随组件渲染,下面分俩种情况说明

获取dom

获取DOM时,通过泛型参数指定具体的DOM元素类型即可

function Foo() {
  // 尽可能提供一个具体的dom type, 可以帮助我们在用dom属性时有更明确的提示
  // divRef的类型为 RefObject<HTMLDivElement>
  const inputRef = useRef<HTMLDivElement>(null)

  useEffect(() => {
    inputRef.current.focus()
  })

  return <div ref={inputRef}>etc</div>
}

如果你可以确保divRef.current 不是null,也可以在传入初始值的位置

// 添加非null标记
const divRef = useRef<HTMLDivElement>(null!)
// 不再需要检查`divRef.current` 是否为null
doSomethingWith(divRef.current)

稳定引用存储器

当做为可变存储容器使用的时候,可以通过泛型参数指定容器存入的数据类型, 在还为存入实际内容时通常把null作为初始值,所以依旧可以通过联合类型做指定

interface User {
  age: number
}

function App(){
  const timerRef = useRef<number | undefined>(undefined)
  const userRes = useRef<User | null> (null)
  useEffect(()=>{
    timerRef.current = window.setInterval(()=>{
      console.log('测试')
    },1000)
    
    
    return ()=>clearInterval(timerRef.current)
  })
  return <div> this is app</div>
}

为Props添加类型

props作为React组件的参数入口,添加了类型之后可以限制参数输入以及在使用props有良好的类型提示

使用interface接口

interface Props {
  className: string
}

export const Button = (props:Props)=>{
  const { className } = props
  return <button className={ className }>Test</button>
}

使用自定义类型Type

type Props =  {
  className: string
}

export const Button = (props:Props)=>{
  const { className } = props
  return <button className={ className }>Test</button>
}

为Props的chidren属性添加类型

children属性和props中其他的属性不同,它是React系统中内置的,其它属性我们可以自由控制其类型,children属性的类型最好由React内置的类型提供,兼容多种类型

type Props = {
  children: React.ReactNode
}

export const Button = (props: Props)=>{
   const { children } = props
   return <button>{ children }</button>
}

:::warning
说明:React.ReactNode是一个React内置的联合类型,包括 React.ReactElementstringnumber React.ReactFragmentReact.ReactPortalbooleannullundefined
:::

为事件prop添加类型

// props + ts
type Props = {
  onGetMsg?: (msg: string) => void
}

function Son(props: Props) {
  const { onGetMsg } = props
  const 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

为事件handle添加类型

为事件回调添加类型约束需要使用React内置的泛型函数来做,比如最常见的鼠标点击事件和表单输入事件:

function App(){
  const changeHandler: React.ChangeEventHandler<HTMLInputElement> = (e)=>{
    console.log(e.target.value)
  }
  
  const clickHandler: React.MouseEventHandler<HTMLButtonElement> = (e)=>{
    console.log(e.target)
  }

  return (
    <>
      <input type="text" onChange={ changeHandler }/>
      <button onClick={ clickHandler }> click me!</button>
    </>
  )
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值