如何在TypeScript中使用React Hook useSt
2021-03-22 本文已影响0人
未定义变量
前言:TypeScript给JavaScript和ReactJS生态系统带来了巨大的变化。它提高了开发效率,TypeScript的项目往往更加可靠,以及在开发过程中更容易排查bug。这篇文章总结了一些我在学习TypeScript中,如何使用useState,并声明state类型。
useState源码
首先,让我们来看看React源码中的useState是如何声明的。
// ...
/**
* Returns a stateful value, and a function to update it.
*
* @version 16.8.0
* @see https://reactjs.org/docs/hooks-reference.html#usestate
*/
function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];
// convenience overload when first argument is ommitted
/**
* Returns a stateful value, and a function to update it.
*
* @version 16.8.0
* @see https://reactjs.org/docs/hooks-reference.html#usestate
*/
function useState<S = undefined>(): [S | undefined, Dispatch<SetStateAction<S | undefined>>];
// ...
在React源码中,useState有两个函数。第二个函数重写(override)了第一个函数,使我们可以在调用useState时不直接声明state变量类型。
值得注意的是,第一个方法接一个名为S的TypeScript泛型,通过它,我们可以定义state的变量类型。
useState基础用法
以下是在TypeScript中使用useState的基本例子。
import React, {useState} from 'react'
export default function App() {
const [name, setName] = useState<string>('未定义变量')
const [age, setAge] = useState<number>(28)
const [isProgrammer, setIsProgrammer] = useState<boolean>(true)
return (
<div>
<ul>
<li>Name: {name}</li>
<li>Age: {age}</li>
<li>Programmer: {isProgrammer ? 'Yes' : 'No'}</li>
</ul>
</div>
)
}
如果你在set函数中的参数不符合声明的变量类型,程序会报错。
import React, {useEffect, useState} from 'react'
export default function App() {
const [name, setName] = useState<string>('未定义变量')
const [age, setAge] = useState<number>(28)
const [isProgrammer, setIsProgrammer] = useState<boolean>(true)
useEffect(() => {
// Error: Argument of type '28' is not assignable to parameter of type 'SetStateAction<string>'.ts(2345)
setName(28)
// Error: Argument of type 'true' is not assignable to parameter of type 'SetStateAction<number>'.ts(2345)
setAge(true)
// Error: Argument of type '"Gabriel Rufino"' is not assignable to parameter of type 'SetStateAction<boolean>'.
setIsProgrammer('未定义变量')
}, [])
return (
<div>
<ul>
<li>Name: {name}</li>
<li>Age: {age}</li>
<li>Programmer: {isProgrammer ? 'Yes' : 'No'}</li>
</ul>
</div>
)
}
但是对于JavaScript原始类型,我们其实不需要声明变量类型,因为TypeScript可以自己判断相应的变量类型。
import React, {useEffect, useState} from 'react'
export default function App() {
const [name, setName] = useState('未定义变量')
const [age, setAge] = useState(28)
const [isProgrammer, setIsProgrammer] = useState(true)
return (
<div>
<ul>
<li>Name: {name}</li>
<li>Age: {age}</li>
<li>Programmer: {isProgrammer ? 'Yes' : 'No'}</li>
</ul>
</div>
)
}
useState进阶用法
当我们需要使用useState处理复杂数据时(如数组或者对象),我们需要借用TypeScript中接口(interface)这个概念。
假设我们需要在useState中声明如下数据。
[
{
"id": 1,
"name": "蔡文姬",
"type": "辅助"
},
{
"id": 1,
"name": "后裔",
"type": "射手"
},
{
"id": 1,
"name": "鲁班7号",
"type": "射手"
}
]
我们需要首先定义一个代表这组数据类型的接口(interface)。
interface IChampion {
id: number;
name: string;
type: string;
}
然后我们在使用useState中,声明我们的state为Champion类型变量。
import React, {useState} from 'react'
interface IChampion {
id: number;
name: string;
type: string;
}
export default function Champions() {
const [champions, setChampions] = useState<IChampion[]>([
{
id: 1,
name: '蔡文姬',
type: '辅助'
},
{
id: 1,
name: '后裔',
type: '射手'
},
{
id: 1,
name: '鲁班7号',
type: '射手'
}
])
return (
<div>
<ul>
{champions.map(champion=> (
<li key={champion.id}>{champion.name} - {champion.type}</li>
))}
</ul>
</div>
)
}
但通常,我们会从API中异步获取数据,而非在useState中直接声明变量。
import React, {useState, useEffect} from 'react'
import axios from 'axios'
interface IChampion {
id: number;
name: string;
type: string;
}
export default function Champions() {
const [champions, setChampions] = useState<IChampion[]>([])
useEffect(() => {
axios.get<IUser[]>('https://api.yourservice.com/champions')
.then(({ data }) => {
setChampions(data)
})
}, [])
return (
<div>
<ul>
{champions.map((champion: IChampion) => (
<li key={champion.id}>{champion.name} - {champion.type}</li>
))}
</ul>
</div>
)
}
以上就是在React TypeScript,useState的一些用法。
--阅读更多文章,请关注我的公众号:未定义变量