TS_React:類型化EventHandler

焦慮可分為有用焦慮無用焦慮兩種。

  1. 有用焦慮指向現(xiàn)在
  2. 無用焦慮指向未來,它的本質(zhì),是對(duì)現(xiàn)在失控的恐懼

大家好,我是柒八九

今天還是--TypeScript實(shí)戰(zhàn)系列的文章。前面的文章中,我們從不同的角度介紹了,TS是如何結(jié)合React進(jìn)行項(xiàng)目開發(fā)的。相關(guān)文章如下。

而今天我們主要是講如何利用TS對(duì)React中的事件回調(diào)進(jìn)行類型化處理。

好了,天不早了。我們開始粗發(fā)。


1. 示例代碼

這是一個(gè)非常簡(jiǎn)單的React應(yīng)用,有一個(gè)input和一個(gè)button。我們用這個(gè)例子來一步步處理,如何用TS處理里面的事件回調(diào)。

import { useState } from 'react';

export default function App() {
  const [inputValue, setInputValue] = useState('');

  const handleInputChange = (event) => {
    setInputValue(event.target.value);
  };

  const handleClick = (event) => {
    console.log('提交被觸發(fā)');
  };

  return (
    <div className="App">
      <h1>前端柒八九</h1>
      <input value={inputValue} onChange={handleInputChange} />
      <button onClick={handleClick}>提交</button>
    </div>
  );
}

2. 添加TS

有幾種方法來類型化上述代碼中的回調(diào)函數(shù),我們將看到3種主要的方法。

  1. 類型化事件處理程序的參數(shù)
  2. 類型化事件處理程序本身
  3. 依靠類型推斷

類型化事件處理程序的參數(shù)(event)

先處理onClick事件。React 提供了一個(gè) MouseEvent 類型,可以直接使用!

import { 
    useState, 
+   MouseEvent,
} from 'react';

export default function App() {
    
  // 省略部分代碼
  
+  const handleClick = (event: MouseEvent) => {
    console.log('提交被觸發(fā)');
  };

  return (
    <div className="App">
      <h1>前端柒八九</h1>
      
      <button onClick={handleClick}>提交</button>
    </div>
  );
}

onClick 事件實(shí)際上是由React維護(hù)的:它是一個(gè)合成事件。
合成事件是React對(duì)瀏覽器事件的一種包裝,以便不同的瀏覽器,都有相同的API。

handleInputChange函數(shù)與 handleClick 非常相似,但有一個(gè)明顯的區(qū)別。不同的是,ChangeEvent 是一個(gè)泛型,你必須提供什么樣的DOM元素正在被使用。

import { 
    useState, 
+   ChangeEvent
} from 'react';

export default function App() {
  const [inputValue, setInputValue] = useState('');

+ const handleInputChange = (event: ChangeEvent<HTMLInputElement>) => {
    setInputValue(event.target.value);
  };

  // 省略部分代碼

  return (
    <div className="App">
      <h1>前端柒八九</h1>
      <input value={inputValue} onChange={handleInputChange} />
      
    </div>
  );
}

在上面的代碼中需要注意的一點(diǎn)是,HTMLInputElement 特指HTML的輸入標(biāo)簽。如果我們使用的是 textarea,我們將使用 HTMLTextAreaElement 來代替。

注意,MouseEvent 也是一個(gè)泛型,你可以在必要時(shí)對(duì)它進(jìn)行限制。例如,讓我們把上面的 MouseEvent 限制為專門從一個(gè)按鈕發(fā)出的鼠標(biāo)事件。

const handleClick = (event: MouseEvent<HTMLButtonElement>) => {
  console.log('提交被觸發(fā)');
};

還需要提示的是,React為我們提供了很多 Event 對(duì)象的類型聲明。

Event 事件對(duì)象類型

事件類型 解釋
ClipboardEvent<T = Element> 剪切板事件對(duì)象
DragEvent<T =Element> 拖拽事件對(duì)象
ChangeEvent<T = Element> Change事件對(duì)象
KeyboardEvent<T = Element> 鍵盤事件對(duì)象
MouseEvent<T = Element> 鼠標(biāo)事件對(duì)象
TouchEvent<T = Element> 觸摸事件對(duì)象
WheelEvent<T = Element> 滾輪時(shí)間對(duì)象
AnimationEvent<T = Element> 動(dòng)畫事件對(duì)象
TransitionEvent<T = Element> 過渡事件對(duì)象

類型化事件處理程序本身

React 聲明文件所提供的 EventHandler 類型別名,通過不同事件的 EventHandler 的類型別名來定義事件處理函數(shù)的類型,更方便定義其函數(shù)類型。

type EventHandler<E extends SyntheticEvent<any>> = {

  bivarianceHack(event: E): void

}['bivarianceHack']

bivarianceHack 為事件處理函數(shù)的類型定義,函數(shù)接收一個(gè) event 對(duì)象,并且其類型為接收到的泛型變量 E 的類型, 返回值為 void。

而在類型定義的時(shí)候,有一個(gè)很怪異的行為['bivarianceHack']。

這與 strictfunctionTypes 下的功能兼容性有關(guān)。在此選項(xiàng)下,如果參數(shù)是派生類型,則不能將其傳遞給將傳入基類參數(shù)的函數(shù)。例如:

class Animal { private x:undefined }
class Dog extends Animal { private d: undefined }

type EventHandler<E extends Animal> = (event: E) => void

let o: EventHandler<Animal> = (o: Dog) => { } // 在 strictFunctionTypes 模式下,失敗

此時(shí),TS會(huì)報(bào)警告。

所以hack的作用是即使在 strictFunctionTypes啟用的情況下允許EventHandler的二元行為。 由于事件處理程序的簽名將在方法聲明中有其來源,因此它不會(huì)受到更嚴(yán)格的函數(shù)檢查。

type BivariantEventHandler<E extends Animal> = { bivarianceHack(event: E): void }["bivarianceHack"];
// 在 strictFunctionTypes 模式下,生效
let o2: BivariantEventHandler<Animal> = (o: Dog) => { } 

講的有點(diǎn)多,我們還是繞回本文的重點(diǎn)。使用EventHandler來對(duì)上面的例子進(jìn)行改造處理。

import { 
   useState, 
+  ChangeEventHandler, 
+  MouseEventHandler 
} from 'react';

export default function App() {
  const [inputValue, setInputValue] = useState('');

 
+ const handleInputChange: ChangeEventHandler<HTMLInputElement> = (event) =>{
    setInputValue(event.target.value);
  };

+  const handleClick: MouseEventHandler = (event) => {
    console.log('提交被觸發(fā)');
  };

  return (
   // ...省略....
  );
}

系不系,很簡(jiǎn)單。


依賴類型推斷

你也可以依靠類型推斷,而不需要自己處理函數(shù)。但是,你需要將回調(diào)函數(shù)內(nèi)聯(lián)處理。

import { useState } from 'react';

export default function App() {
  const [inputValue, setInputValue] = useState('');

  return (
    <div className="App">
      <h1>前端柒八九</h1>
      <input 
        value={inputValue} 
+        onChange={(event) => setInputValue(event.target.value)}
      />
      <button 
+        onClick={(event) => console.log('提交被觸發(fā)')}
      >
        提交
      </button>
    </div>
  );
}

這個(gè)更簡(jiǎn)單


后記

分享是一種態(tài)度。

參考資料:

全文完,既然看到這里了,如果覺得不錯(cuò),隨手點(diǎn)個(gè)贊和“在看”吧。

本文由mdnice多平臺(tái)發(fā)布

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容