TypeScript中常见Hooks的使用

1,583 阅读19分钟

useEffect

在TS中,useEffect的使用和JS完全一致

useEffect(()=>{
},[需要监听的数据])

useEffect的类型声明格式

// ? 表示可选
// DependencyList 是一个 Readonly any[]
function useEffect(effect: EffectCallback, deps?: DependencyList): void;

useState

useState的类型声明格式

function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];

标准用法(Js中的用法)

useState接收一个泛型参数,用于指定初始值的类型

示例:

// 使用泛型
const [name, setName] = useState<string>('张三')
const [age, setAge] = useState<number>(28)
const [isProgrammer, setIsProgrammer] = useState<boolean>(true)

// 如果你在set函数中的参数不符合声明的变量类型,程序会报错
<button onClick={() => setName(100)}>按钮</button>  // 报错

简单用法

在使用useState的时候,只要提供了初始值,typescript会自动根据初始值进行类型推断,因此useState的泛型参数可以省略(就是TS的类型推论)

示例:

const [name, setName] = useState('张三')
const [age, setAge] = useState(28)
const [isProgrammer, setIsProgrammer] = useState(true)

注意:useState本身是需要接受泛型参数的,但是由于TS的类型推论机制,所以这个泛型参数就可以省略

进阶用法

场景:发送请求向后台服务器获取数据

JS初始写法

import { useEffect, useState } from 'react'
import axios from 'axios'

export default function App() {
  // 存放频道列表数据
  const [list, setList] = useState([])
  useEffect(() => {
    const fetchData = async () => {
      const res = await axios.get('http://geek.itheima.net/v1_0/channels')
      setList(res.data.data.channels)
    }
    fetchData()
  }, [])
  return (
    <div>
      <ul>
        {list.map((item) => {
          return <li key={item.id}>{item.name}</li> {/*这里会报错:*/}
        })}
      </ul>
    </div>
  )
}

此时会遇到错误,

解决方案:

  1. 提前给初始值,便于类型推导

    const [list, setList] = useState([{id:1, name: 'test'}])

  2. 补充泛型参数:any大法

    const [list, setList] = useState<any[]>([])

  3. 补充泛型参数:按接口返回值自定义类型

    type Channel = { id: number, name: string}[]​const [list, setList] = useState<Channel[]>([])
    

useRef

useRef的类型声明格式:

function useRef<T>(initialValue: T): MutableRefObject<T>;
    
interface MutableRefObject<T> {
    current: T;
}

注意:useRef的泛型参数用于指定current属性的值的类型

使用useRef操作DOM,需要明确指定所操作的DOM的具体的类型,否则current属性会是null

const Ref=useRef<HTML'DOM元素类型'ELEment>(null)

示例:

const inputRef = useRef<HTMLInputElement>(null)  //null可以代表对象类型

在jsx中,鼠标直接移动到该元素上,就会显示出来该元素的类型

useSelector

useSelector接收两个泛型参数

  • 第一个泛型类型:TState的默认值是DefaultRootState(就是{})用于指定state的类型

  • 第二个泛型类型:TSelected用于指定返回值的类型

    //useSelector类型声明格式 export function useSelector<TState = DefaultRootState, TSelected = unknown>( selector: (state: TState) => TSelected, equalityFn?: (left: TSelected, right: TSelected) => boolean ): TSelected;

    //类型为 unknown 时,不能使用该类型的属性和方法但是可以为其赋值,直接使用会报错

解决方案1:

  • 指定泛型类型

示例:

const todos = useSelector<{todos:[]} ,{id:number, name:string,isDone:boolean}[]>(state => state.todos)

解决方案2:

  • 直接指定回调函数的形参类型

示例:

const todos = useSelector((state: {todos:{id:number, name:string,isDone:boolean}[]})  => state.todos)

useDispatch

基本用法

const dispatch = useDispatch()  //此时与JS中的写法一直,用法也是一样的

进阶用法

useDispatch可以接收一个泛型参数用于指定Action的类型

示例:

import { Dispatch } from "react"
import { useSelector, useDispatch } from "react-redux"

import { RootStateType } from '../store'
export default function Home() {
    const dispatch = useDispatch<Dispatch<{type:string,payload:any}>>()
    dispatch({
        type: 'abc',
        payload: 123
    })

useHistory

作用:可以用来做路由之间的跳转,并且在跳转时可以指定跳转参数state的类型

useHistory类型声明格式

export function useHistory<HistoryLocationState =
 H.LocationState>(): H.History<HistoryLocationState>;

路由传参

语法:

const history = useHistory()
// 方式1
history.push('/home', { a:1 })
// 方式2
history.push({pathname: '/home', state:{a:1 }})

如果希望跳转传参时,有指定的格式,可以给useHistory泛型提供类型参数

const history = useHistory<{a: number }>()

获取路由参数

场景:通过useLocation 来获取上一个页面传递的参数。

js的基本格式:

// 原来js的写法
import { useLocation } from 'react-router'
const location = useLocation()
const aa = location.state.a 
// 这里的a就是上一个页面中通过state传进来的

进阶用法

通过 useHistory可以通过泛型参数来指定state的类型

import { useLocation } from 'react-router'
export default function Home() {    
    const location = useLocation<{ a: string }>()    
    const a = location.state?.a
}

useParams

作用:useParams接收一个泛型参数,用于指定params对象的类型

useParams类型声明格式

export function useParams<Params extends { [K in keyof Params]?: string } = {}>(): Params;

注意:使用useParams中的属性时,需提前定义一个泛型参数,由useParams来接受,直接使用会报错