使用React Hooks和TypeScript - Web前端
作者:98wpeu发布时间:2026-09-07分类:网页前端技术浏览:3
Hook于2019年2月引入react,以提高代码的可读性。我们已经在之前的文章中讨论过React钩子,但是这次我们正在研究钩子如何与TypeScript一起工作。

在使用钩子之前,React组件曾经具有两种风格:
处理状态的类
由其道具完全定义的功能
这些的自然用法是使用类构建复杂的容器组件,并使用纯函数构建简单的表示性组件。
什么是React挂钩?
容器组件处理状态管理和对服务器的请求,然后在本文中将其称为副作用。状态将通过道具传播到容器子级。
但是随着代码的增长,功能组件倾向于转换为容器组件。
将功能组件升级为更智能的组件并不是一件痛苦的事情,但这是一项耗时且令人不愉快的任务。此外,不再严格要求区分演示者和容器。
钩子可以做到这两者,因此生成的代码更加统一,并且几乎具有所有优点。这是将局部状态添加到正在处理报价签名的小型组件中的示例。
// put signature in local state and toggle signature when signed changes
function QuotationSignature({quotation}) {
const [signed, setSigned] = useState(quotation.signed);
useEffect(() => {
fetchpost(`quotation/${quotation.number}/sign`)
}, [signed]); // effect will be fired when signed changes
return <>
<input type="checkbox" checked={signed} onChange={() => {setSigned(!signed)}}/>
Signature
</>
}这有很大的好处:使用Typescript进行编码对于angular来说很棒,但是对React却臃肿了。但是,使用TypeScript编写React钩子是一种令人愉快的体验。
具有旧React的TypeScript
TypeScript是由microsoft设计的,并在React开发Flow时遵循了Angular的路径,而Flow现在已经失去了吸引力。写作阵营与天真打字稿类是相当痛苦的,因为阵营开发商必须输入两个props和state即使许多键是一样的。
这是一个简单的域对象。我们制作一个带类型的报价应用,该应用Quotation在带有状态和道具的某些原始组件中进行管理。将Quotation可以创建,其关联的状态可以改变,以签署与否。
interface Quotation{
id: number
title:string;
lines:QuotationLine[]
PRice: number
}
interface QuotationState{
readonly quotation:Quotation;
signed: boolean
}
interface Quotationprops{
quotation:Quotation;
}
class QuotationPage extends Component<QuotationProps, QuotationState> {
// ...
}但是,假设QuotationPage现在将向服务器询问ID:例如,公司的第678条报价。好吧,这意味着QuotationProps不知道那个重要的数字-它没有完全包装Quotation 。我们必须在QuotationProps接口中声明更多代码:
interface QuotationProps{
// ... all the attributes of Quotation but id
title:String;
lines:QuotationLine[]
price: number
}我们将ID以外的所有属性复制为新类型。嗯 这让我想到了旧的java,其中涉及编写大量的DTO。为了克服这个问题,我们将增加我们的TypeScript知识来绕过痛苦。
带钩子的TypeScript的好处
通过使用钩子,我们将能够摆脱以前的QuotationState接口。为此,我们将QuotationState分成状态的两个不同部分。
interface QuotationProps{
quotation:Quotation;
}
function QuotationPage({quotation}:QuotationProps){
const [quotation, setQuotation] = useState(quotation);
const [signed, setSigned] = useState(false);
}通过分割状态,我们不必创建新接口。本地状态类型通常是通过默认状态值来推断的。
带有钩子的组件都是功能。因此,我们可以编写返回FC<P>React库中定义的类型的相同组件。该函数显式声明其返回类型,并沿props类型进行设置。
const QuotationPage : FC<QuotationProps> = ({quotation}) => {
const [quotation, setQuotation] = useState(quotation);
const [signed, setSigned] = useState(false);
}显然,将TypeScript与React钩子一起使用比在React类中使用它更容易。并且由于强类型是确保代码安全的宝贵安全性,因此如果新项目使用钩子,则应考虑使用TypeScript。如果要使用TypeScript,一定要使用钩子。
可以使用或不使用React来避免TypeScript的原因有很多。但是,如果您选择使用它,则也一定要使用钩子。
适用于钩子的TypeScript的特定功能
在前面的React hooks TypeScript示例中,我在QuotationProps中仍然具有number属性,但是仍然不知道该数字实际是什么。
TypeScript为我们提供了一长串的实用程序类型,其中三个可以通过减少许多接口描述的噪音来帮助我们使用React。
Partial<T>:T的任何子键Omit<T, 'x'>:T的所有键,除了键xPick<T, 'x', 'y', 'z'>:完全x, y, z来自T

在我们的情况下,我们想Omit<Quotation, 'id'>省略引号的ID。我们可以使用type关键字动态创建一个新类型。
Partial<T>并且Omit<T>在大多数类型的语言(例如Java)中不存在,但是对于前端开发中的FORMs的示例有很大帮助。它简化了打字的负担。
type QuotationProps= Omit<Quotation, id>;
function QuotationPage({quotation}:QuotationProps){
const [quotation, setQuotation] = useState(quotation);
const [signed, setSigned] = useState(false);
// ...
}现在,我们有一个没有ID的报价单。因此,也许我们可以设计一个Quotation和PersistedQuotation extends Quotation。此外,我们将很容易解决一些反复发作if或undefined问题。尽管它不是完整的对象,我们是否仍应将其引用为变量?这超出了本文的范围,但是无论如何我们稍后都会提到。
但是,现在我们确定我们不会散布我们认为具有的对象number。使用Partial<T>并不能带来所有这些保证,因此请谨慎使用。
Pick<T, ‘x’|’y’>是动态声明类型的另一种方式,而不必声明新接口。如果是组件,只需编辑“报价”标题:
type QuoteEditformProps= Pick<Quotation, 'id'|'title'>
要不就:
function QuotationNameEditor({id, title}:Pick<Quotation, 'id'|'title'>){ ...}不要判断我,我是DOMAIn Driven design的忠实拥护者。我并不懒惰,不想为新接口再写两行。我使用接口来精确描述域名,使用这些实用程序功能来确保本地代码正确性,从而避免噪音。读者将知道这Quotation是规范的界面。
React钩子的其他好处
React团队始终将React视为功能框架。他们使用了类,以便组件可以处理其自己的状态,并且现在将其作为一种允许函数跟踪组件状态的技术进行了挂钩。
interface Place{
city:string,
country:string
}
const initialState:Place = {
city: 'Rosebud',
country: 'USA'
};
function reducer(state:Place, action):Partial<Place> {
switch (action.type) {
case 'city':
return { city: action.Payload };
case 'country':
return { country: action.payload };
}
}
function PlaceForm() {
const [state, dispatch] = Usereducer(reducer, initialState);
return (
<form>
<input type="text" name="city" onChange={(event) => {
dispatch({ type: 'city',payload: event.target.value})
}}
value={state.city} />
<input type="text" name="country" onChange={(event) => {
dispatch({type: 'country', payload: event.target.value })
}}
value={state.country} />
</form>
);
}在这种情况下,使用Partial是安全且不错的选择。
尽管一个函数可以执行多次,但是关联的useReducer钩子只会被创建一次。
通过自然地从组件中提取reducer函数,可以将代码分为多个独立的函数,而不是一个类中的多个函数,所有这些都链接到该类中的状态。
显然,这对于可测试性更好—一些功能处理JSX,其他功能处理行为,其他功能处理业务逻辑,等等。
您(几乎)不再需要高阶组件。Render props模式更易于使用函数编写。
因此,阅读代码更加容易。您的代码不是类/函数/模式的流,而是函数的流。但是,由于您的功能未附加到对象,因此可能很难命名所有这些功能。
TypeScript仍然是javascript
JavaScript很有趣,因为您可以在任何方向撕开您的代码。使用TypeScript,您仍然可以使用keyof对象的键进行播放。您可以使用类型并集来创建无法读取和无法维护的内容-不,我不喜欢这些。您可以使用类型别名将字符串假装为UUID。
但是您可以在没有安全的情况下执行此操作。确保您tsconfig.json可以"strict":true选择。在项目开始之前检查它,否则您将不得不重构几乎每一行!
关于您在代码中键入的级别存在争议。您可以键入所有内容,或让编译器推断类型。这取决于棉短绒的配置和团队的选择。
此外,您仍然可以犯运行时错误!TypeScript比Java更简单,并且避免了使用泛型的协方差/协方差问题。
在此动物/猫[https://stackblitz.com/edit/robusta-react-ts?file=index.tsx]示例中,我们具有与猫列表相同的动物列表。不幸的是,这是第一行的合同,而不是第二行。然后,将鸭子添加到“动物”列表中,因此“猫”列表为假。
interface Animal {}
interface Cat extends Animal {
meow: () => string;
}
const duck = {age: 7};
const felix = {
age: 12,
meow: () => "Meow"
};
const listOfAnimals: Animal[] = [duck];
const listOfCats: Cat[] = [felix];
function MyAPP() {
const [cats , setCats] = useState<Cat[]>(listOfCats);
// Here the thing: listOfCats is declared as a Animal[]
const [animals , setAnimals] = useState<Animal[]>(listOfCats)
const [animal , setAnimal] = useState(duck)
return <div onClick={()=>{
animals.unshift(animal) // we set as first cat a duck !
setAnimals([...animals]) // dirty forceupdate
}
}>
The first cat says {cats[0].meow()}</div>;
}TypeScript对于泛型只有一种双变量方法,该方法很简单,可以帮助Javascript开发人员采用。如果你正确地命名变量,你很少会添加duck到listOfCats。
另外,有提议增加和减少协方差和协方差的合同。
结论
我最近回到Kotlin,这是一种很好的类型化语言,正确地键入复杂的泛型非常复杂。由于鸭子输入和双变量方法的简单性,TypeScript没有这种一般性的复杂性,但是您还有其他问题。也许您并没有为使用TypeScript设计并为TypeScript设计的Angular遇到很多问题,但使用React类却遇到了这些问题。
TypeScript可能是2019年的大赢家。它获得了React,但也通过node.js征服了后端世界,并以非常简单的声明文件键入旧库的能力。它埋藏了Flow,尽管有些原因与ReasonML一起进行。
现在,我觉得hooks + TypeScript比Angular更令人愉快和高效。
相关推荐
- React中功能组件和类组件之间的区别 - Web前端
- 带大家学习一款很实用的Vue多选列表组件:multiselect - Web前端
- 如何将您的应用程序从Express迁移到Fastify - Web前端
- 如何在MySQL数据库中使用JSON数据字段 - Web前端
- 产品经理为何要学习Web前端编码 - Web前端
- Vue内置组件:熟悉keep-alive的来龙去脉 - Web前端
- React开发:提交输入框input值的小应用 - Web前端
- 使用现代JavaScript和Web组件构建Web应用程序 - Web前端
- Windows 10:绘画和截图工具现在可以从Microsoft Store更新 - Web前端
- 为什么会报错SyntaxError: JSON.parse: bad parsing? - Web前端
- 网页前端技术排行
-
- 1[Web前端]用javascript实现默认图片替代未显示的图片 - Web前端
- 2分析Iconfont-阿里巴巴矢量常用图标库 - Web前端
- 3jQuery实例教程:制作网页中可折叠的面板 - Web前端
- 4【第六章】Foundation之按钮和下拉功能 - Web前端
- 5基于jquery的滚动条滚动固定div(附演示下载) - Web前端
- 6jQuery编写widget的一些技巧分享 - Web前端
- 7分享精心挑选的12款优秀jQuery Ajax分页插件和教程 - Web前端
- 8在Mac/PC上远程调试iPhone/iPad上的网页 - Web前端
- 9jQuery实现鼠标移到元素上动态提示消息框效果 - Web前端
- 最近发表
-
- WordPress随机显示特色图片插件:Random Post Thumbnails
- KeePass实现Chrome浏览器自动填充密码方法一
- LNMP一键包nginx 301强制跳转到https教程
- KeePass实现Chrome浏览器自动填充密码方法二
- #建站# 免费的VPS管理软件Xshell8/Xftp8中文版下载
- 使用Xshell 8连接VPS教程_电脑登录vps的方法
- WordPress评论界面添加烟花????效果
- 不同浏览器书签同步方案:坚果云+Floccus_详细使用教程
- iOS端KeePassXC客户端APP:Strongbox Password Safe
- 给WordPress评论中的Gravatar头像图片添加ALT属性


