TypeScript && React


環境搭建

我們當然可以先用腳手架搭建React項目,然后手動配置成支持TypeScript的環境,雖然比較麻煩,但可以讓你更清楚整個過程。這里比較麻煩,就不演示了,直接用命令配置好。

npx create-react-app appname --typescript

可以安裝一些自己需要的庫及其聲明文件,例如react-router-dom、axios、ant Design等。如果要安裝ant design,還需要在開發環境庫中安裝一些依賴庫,以幫助實現按需加載。

使用

有類型約束的函數組件

import React from "react";
import { Button } from "antd";

interface Greeting {
   name: string;
   firstName?: string;
   lastName?: string;
}

// 沒有使用React.FC
const HelloOld = (props: Greeting) => <Button>你好{props.name}</Button>;

// 使用React.FC泛型類型
const Hello: React.FC<Greeting> = (props) => {
   return (
      <Button>Hello {props.name}</Button>
   )
};

export { Hello, HelloOld };

定義函數組件時,使用React.FC與不使用沒有太多區別,沒有為我們帶來明顯的好處,建議使用常規定義方式。關於使用與不使用的區別,詳見 https://github.com/facebook/create-react-app/pull/8177

有類型約束的類組件

import React,{Fragment} from "react";
import { Button } from "antd";

interface Greeting {
   name: string;
   firstName?: string;
   lastName?: string;
}
interface State {
   count: number
}

// 泛型類型,第一個傳入參數約束屬性props,第二個約束狀態state(內部數據)
class HelloClass extends React.Component<Greeting, State> {
   state: State = {
      count: 0
   };
   static defaultProps = {  // 屬性默認值
      firstName: "",
      lastName: "",
   };

   render() {
      return (
         <Fragment>
            <p>點擊了{this.state.count}次</p>
            <Button onClick={()=>{this.setState({count: this.state.count+1})}}>Hello{this.props.name}Class</Button>
         </Fragment>
      );
   }
}

export default HelloClass;

有類型約束的高階組件

import React from "react";
import HelloClass from "./HelloClass";

interface Loading {
   loading: boolean;
}

function HelloHoc<P>(params?: any) {
   return function<P>(WrappedComponent: React.ComponentType<P>) { // P表示被包裝組件的屬性的類型
      return class NewComponent extends React.Component<P & Loading>{ // 這里使用交叉類型,為新組件增加一些屬性,接口Loading定義了新增的屬性聲明
         render(){
            return this.props.loading ? <div>Loading</div> : <WrappedComponent {...this.props as P}/>

         }
      }
   }
}

export default HelloHoc()(HelloClass);

高階組件在ts中使用會有比較多的類型問題,解決這些問題通常不會很順利,而且會存在一些已知的bug,這不是高階組件本身的問題,而是React聲明文件還沒有很好地兼容高階組件的類型檢查,更好的方式是使用Hooks

有類型約束的Hooks

import React, { useState, useEffect } from "react";
import { Button } from "antd";

interface Greeting {
   name: string;
   firstName?: string;
   lastName?: string;
}

const HelloHooks = (props: Greeting) => {
   const [ count, setCount ] = useState(0); // 設了初值,所以不用定義類型
   const [ text, setText ] = useState<string | null>(null);

   useEffect(()=>{
      count > 5 && setText("休息一下");
   },[count]); // 第二個參數的作用是,只有當count改變的時候,函數內的邏輯才會執行。

   return (
      <>
         <p>你點擊了Hooks {count} 次 {text}</p>
         <Button onClick={()=>{setCount(count+1)}}>{props.name}</Button>
      </>
   );
};

export default HelloHooks;

事件綁定

class HelloClass extends React.Component<Greeting, State> {
   state: State = {
      count: 0
   };

   clickHandle = (e: React.MouseEvent) => { // 事件對象e的類型使用內置的合成事件。在回調函數中,e的屬性都會無效
      e.persist(); // 將該事件從池中刪除合成事件,可以正常使用
      console.log(e);
      // this.setState({count: this.state.count+1})
   };

   inputHandle = (e: React.FormEvent<HTMLInputElement>) => {
      // e.persist();
      console.log(e.currentTarget.value); // 此時編譯器報錯,認為沒有value屬性,需要指定<HTMLInputElement>泛型類型
      // console.log(e.target.value); // 仍然不行
   };

   render() {
      return (
         <Fragment>
            <p>點擊了{this.state.count}次</p>
            <Button onClick={this.clickHandle}>Hello{this.props.name}Class</Button>
            <input onChange={this.inputHandle}/>
         </Fragment>
      );
   }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM