使用 TypeScript + React + Redux 進行項目開發(入門篇,附源碼)

本文詳細介紹瞭如何使用 Create-React-App 編寫 TypeScript + React 項目css

前言

對於 TypeScript + React 開發,MicroSoft 編寫了一個 TypeScript-React-Starter 的例子,Github 地址。有須要的朋友能夠去看一下。html

我本身也看了一下,文檔說明講解的很好,可是 Demo 拉下來卻沒法正常運行,一直報錯。因此我本身使用 TypeScript + React + Redux 寫了 Demo,做爲範例來用一下。node

本文 Demo 地址

  • 本文 Counter Demo 是一個簡易的例子,能夠用來做爲入門參考,Counter Demoreact

  • 另外還寫了一個 TodoList 的例子,稍微更有難度一些,代碼量和組件更多更詳細。有須要的朋友也能夠參考一下。TodoList Demogit

建議

能夠先下載 Counter Demo 後,運行項目,查看運行效果,而後對照本文進行閱讀,效果更佳!github

使用 TypeScript 編寫 React 須要注意的規範

  • 必須遵照的要求:typescript

    • 全部用到 jsx 語法的文件都須要以 tsx 後綴命名
    • 使用組件聲明時的 Component<P, S> 泛型參數聲明,來代替 PropTypes進行類型校驗
  • 額外的代碼規範:npm

    • 全局變量或者自定義的 window 對象屬性,統一在項目根下的 global.d.ts 中進行聲明定義
    • 對於項目中經常使用到的接口數據對象,最好在 types/ 目錄下定義好其結構化類型聲明

安裝 Create-React-App

$ npm install create-react-app -g
複製代碼

建立項目

先建立一個新的項目,這裏咱們命名爲 typescript-react-app

$ create-react-app typescript-react-app --scripts-version=react-scripts-ts
複製代碼

react-scripts-ts是一系列適配器,它利用標準的create-react-app工程管道並把TypeScript混入進來。json

項目建立成功後,此時項目結構以下所示:redux

my-app/
├─ node_modules/
├─ public/
├─ src/
│  └─ ...
├─ .gitignore
├─ images.d.ts
├─ package.json
├─ README.md
├─ tsconfig.json
├─ tsconfig.prod.json
├─ tsconfig.test.json
├─ tslint.json
└─ yarn.lock
複製代碼

注意:

  • tsconfig.json包含了工程裏TypeScript特定的選項。
  • tslint.json保存了要使用的代碼檢查器的設置,TSLint。
  • package.json包含了依賴,還有一些命令的快捷方式,如測試命令,預覽命令和發佈應用的命令。
  • public包含了靜態資源如HTML頁面或圖片。除了index.html文件外,其它的文件均可以刪除。
  • src包含了TypeScript和CSS源碼。index.tsx是強制使用的入口文件。

運行項目

先運行項目,看看是否可以正常啓動,若是能夠,說明項目建立沒有問題。 運行命令:

$ npm run start

# 或者運行 yarn run start
複製代碼

React 配合 TypeScript 的基本使用

在當前項目中,能夠看到 index.tsx 和 App.jsx 文件中已經使用了 TypeScript,咱們如今本身來用 TypeScript 編寫一個 React 組件吧。

定義一個 Counter 組件

咱們在 src 下建立一個 components 目錄,新增 Counter 組件:

Counter.tsx

import * as React from 'react';


// 建立類型接口
export interface Iprops {
    value: number
}

// 使用接口代替 PropTypes 進行類型校驗
const Counter = ({ value }: Iprops) => {
    return <p>Clicked: { value } times</p>
}

export default Counter;
複製代碼

在 App.tsx 中引用 Counter 組件並展現

import * as React from 'react';
import './App.css';

import Counter from './components/Counter.jsx';
// import logo from './logo.svg';

class App extends React.Component {
  public render() {
    return (
      <div className="App">
        <Counter value={ 0 } />
      </div>
    );
  }
}

export default App;
複製代碼

運行項目:npm run start,能夠看到瀏覽器中展現出了 Clicked: 0 times,說明咱們第一個 Counter 組件已經編寫並使用成功了。

使用類的方式定義 Counter 組件

剛纔是使用函數組件的方式定義的 Counter 組件,如今咱們使用類的方式來改寫一下。兩種方式都試一試:

Counter.tsx

import * as React from 'react';


// 建立類型接口
export interface IProps {
    value: number
}

// 使用接口代替 PropTypes 進行類型校驗
export default class Counter extends React.PureComponent<IProps> {
    public render() {
        return <p>Clicked: { this.props.value } times</p>
    }
}
複製代碼

進階:在項目中配合 Redux 進行使用

安裝項目須要的插件

安裝redux和react-redux以及它們的類型文件作爲依賴。

$ npm install -S redux react-redux @types/react-redux
複製代碼

這裏咱們不須要安裝@types/redux,由於Redux已經自帶了聲明文件(.d.ts文件)。

定義應用的狀態 State

通常會將經常使用的結構類型存放到 /types 目錄下。因此咱們在 src 目錄下新建 types 目錄。 此時項目中只有一個 state,就是 Counter 中的點擊次數,因此就沒有使用藉口來做爲約束,而是直接使用了 type。

type/index.tsx

// 定義 State 結構類型
export type StoreState = number;
複製代碼

添加 actions

在 src 下建立 constants 目錄,在 index.tsx 文件中添加須要響應的消息類型

constants/index.tsx

// 定義增長 state 類型常量
export const INCREMENT = "INCREMENT";
export type INCREMENT = typeof INCREMENT;

// 定義減小 state 類型常量
export const DECREMENT = "DECREMENT";
export type DECREMENT = typeof DECREMENT;
複製代碼

這裏的const/type模式容許咱們以容易訪問和重構的方式使用TypeScript的字符串字面量類型。 接下來,咱們建立一些 actions 以及建立這些 actions 的函數,src/actions/index.tsx。

actions/index.tsx

export interface IINCREMENTAction {
    type: INCREMENT;
}

export interface IDECREMENTAction {
    type: DECREMENT;
}

// 定義 modifyAction 類型,包含 IINCREMENTAction 和 IDECREMENTAction 接口類型
export type ModifyAction = IINCREMENTAction | IDECREMENTAction;


// 增長 state 次數的方法
export const increment = (): IINCREMENTAction => ({
    type: INCREMENT,
})

// 減小 state 次數的方法
export const decrement = (): IDECREMENTAction => ({
    type: DECREMENT
})
複製代碼

actions/index.tsx 中定義了兩個類型,分別負責添加和減小操做的行爲。咱們還定義了一個類型(ModifyAction),它描述了哪些 action 是能夠增長或減小的。 最後,咱們定義了兩個函數用來建立實際的 actions

添加 reducer

咱們的reducer將放在src/reducers/index.tsx文件裏。 它的功能是保證增長操做會讓 times 加1,減小操做則要將 times 減1。

reducers/index.tsx

import { ModifyAction } from '../actions';
import { DECREMENT, INCREMENT } from '../constants';


// 處理並返回 state 
export default (state = 0, action: ModifyAction): number => {
    switch (action.type) {
      case INCREMENT:
        return state + 1
      case DECREMENT:
        return state - 1
      default:
        return state
    }
}
複製代碼

建立容器組件

以前咱們已經使用了 Counter 組件,可是這個組件是一個純組件,此時咱們須要一個組件將 Counter 和 數據鏈接起來。咱們先修改一下原先的 Counter 組件,在其中添加一些操做按鈕

components/Counter.tsx

import * as React from 'react';


// 建立類型接口
export interface IProps {
    value: number,
    onIncrement: () => void,
    onDecrement: () => void
}

// 使用接口代替 PropTypes 進行類型校驗
export default class Counter extends React.PureComponent<IProps> {
    public render() {
        const { value, onIncrement, onDecrement } = this.props;
        return (
            <p>
                Clicked: { value } times
                <br />
                <br />
                <button onClick={ onIncrement } style={{ marginRight: 20 }}> +  </button>
                <button onClick={ onDecrement }> - </button>
            </p>
        )
    }
}

複製代碼

而後咱們再建立一個 container 目錄,用來存放須要與數據交互的組件,新建 CounterCon.tsx 文件.

兩個關鍵點是初始的 Counter 組件和 react-reduxconnect 函數。 connect 能夠將咱們的 Counter 組件轉換成一個容器,經過如下兩個函數:

  • mapStateToProps將當前store裏的數據以咱們的組件須要的形式傳遞到組件。
  • mapDispatchToProps利用dispatch函數,建立回調props將actions送到store。

container/CounterCon.tsx

import { connect } from 'react-redux';
import { Dispatch } from 'redux';

import { decrement, increment } from '../actions';
import Counter from '../components/Counter';
import { StoreState } from '../types';


// 將 reducer 中的狀態插入到組件的 props 中
const mapStateToProps = (state: StoreState): { value: number } => ({
    value: state
})

// 將 對應action 插入到組件的 props 中
const mapDispatchToProps = (dispatch: Dispatch) => ({
    onDecrement: () => dispatch(decrement()),
    onIncrement: () => dispatch(increment())
})

// 使用 connect 高階組件對 Counter 進行包裹
export default connect(mapStateToProps, mapDispatchToProps)(Counter);
複製代碼

建立 store

讓咱們回到src/index.tsx。 要把全部的東西合到一塊兒,咱們須要建立一個帶初始狀態的store,並用咱們全部的reducers來設置它。 而且使用 react-redux 的 Provider 將 props 和 容器鏈接起來

index.tsx

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore } from 'redux';

import App from './App';
import './index.css';
import reducer from './reducer'; 
import registerServiceWorker from './registerServiceWorker';


// 一、建立 store
const store = createStore(reducer);

ReactDOM.render(
    // 二、而後使用react-redux的Provider將props與容器連通起來
    <Provider store={ store }>
        <App />
    </Provider> ,
    document.getElementById('root') as HTMLElement
);
registerServiceWorker();
複製代碼

回到咱們的 App.jsx 文件中,以前咱們引用的是 components 中的 Counter 組件,可是此時咱們須要使用的是與數據有交互的 CounterCon 組件。改寫以下:

App.jsx

import * as React from 'react';
import './App.css';

// 引入 container 組件 CountCon
import CountCon from './container/CountCon';
// import logo from './logo.svg';

class App extends React.Component {
  public render() {
    return (
      <div className="App"> <CountCon /> </div>
    );
  }
}

export default App;
複製代碼

注意,此時 CountCon 再也不須要 props 了,由於咱們使用了 connect 函數爲包裹起來的 Hello 組件的 props 適配了應用的狀態。

此時,運行項目,點擊 + 或者 - 按鈕,便可看到 times 的次數會發生變化。

總結

至此,對於使用 TypeScript 編寫 React 應用應該有了必定的瞭解。其實寫法也比較固定,剛接觸的話可能有些地方容易出現問題,多寫幾個組件以後,應該就沒什麼問題了。 在編寫項目的過程當中,create-react-app 自帶的 tslint 可能要求比較嚴嚴格,好比:

  • 在標籤裏不容許使用 lambda 表達式,在 tslint.json 文件 rules 屬性中添加:"jsx-no-lambda": false 便可
  • 在導入模塊時,必須按照字母順序導入,在 tslint.json 文件 rules 屬性中添加:"ordered-imports": false 便可

還有不少別的配置,有須要的話,能夠查看文檔:TSLint core rules


本文 Demo 地址

  • 本文 Counter Demo 是一個簡易的例子,能夠用來做爲入門參考:Counter Demo

  • 另外還寫了一個 TodoList 的例子,稍微更有難度一些,代碼量和組件更多更詳細。有須要的朋友也能夠參考一下:TodoList Demo

相關文章
相關標籤/搜索