1. 程式人生 > >redux-form(V7.4.2)筆記(三)之Flow簡介

redux-form(V7.4.2)筆記(三)之Flow簡介

企業 pes 大型 ofo value 要花 pro 源文件 lda

為什麽要學習redux-form?

我們知道,react-redux為React開發提供了科學的存儲管理方案。另一方面,類似Semantic-UI與Material UI,Ant-UI等則提供了比較全面的基於React組件框架的UI解決方案。但問題在於,後者提供的UI方案還有很大的局限性,特別是對於form表單的各種應用需求支持方面。為此,相對於簡單的表單應用,為了減少重復冗余的代碼,我們可以去使用redux-form-utils庫,此庫能利用高階組件的特性為表單的每個字段提供value和onChange等必須值,而無需你手動創建。但是,對於復雜的表單,redux-form-utils庫顯得捉襟見肘;此時,轉而利用redux-form即成為最佳方案。這是因為redux-form庫除了提供表單必須的字段支持外,redux-form還能實現表單同步驗證、異步驗證甚至嵌套表單等復雜功能。

Javascript靜態類型檢查工具Flow

為什麽存在和要使用Flow?要回答這個問題必須提起微軟的TypeScript語言。一提起TypeScript,還不得不提起微軟的JScript。JScript是由微軟公司開發的活動腳本語言,是微軟對ECMAScript規範的實現。JScript最初是隨Internet Explorer 3.0於1996年8月發布。在網絡程序員談論Internet Explorer中的JavaScript的時候,他們實際上是指JScript。和其他活動腳本一樣,它後來也被Windows Script Host(WSH)和Active Server Pages所支持。典型的JScript源文件使用的擴展名是.js。JScript最新的版本是基於尚未定稿的ECMAScript4.0版規範的JScript .NET,並且可以在微軟的.Net環境下編譯。JScript在ECMA的規範上增加了許多特性。

TypeScript 是一種由微軟開發的自由和開源的編程語言,它是JavaScript的一個超集,擴展了JavaScript的語法。現有的 JavaScript 代碼可與 TypeScript 一起工作無需任何修改,TypeScript 通過類型註解提供編譯時的靜態類型檢查。TypeScript 可處理已有的 JavaScript 代碼,並只對其中的 TypeScript 代碼進行編譯。

Flow是個JavaScript的靜態類型檢查工具,由Facebook出品的開源碼項目,問世只有一年多,是個相當年輕的項目。簡單來說,它是對比TypeScript語言的解決方式。Flow本質上也只是個檢查工具,它並不會自動修正代碼中的錯誤,也不會強制說你沒按照它的警告消息修正,就不會讓你運行程序。當然,並沒有要求什麽時候一定要用這類的工具,只是這種作法可以讓你的代碼更具強健性與提高閱讀性,也可以直接避去很多不必要的數據類型使用上的問題,這種開發方式目前在許多框架與函數庫項目,或是以JavaScript應用為主的開發團隊中都已經都是必用工具。

JavaScript是一種弱(動態)數據類型的語言,弱(動態)數據類型代表在代碼中,變量或常量會自動依照賦值變更數據類型,而且類型種類也很少,這是直譯式腳本語言的常見特性,但有可能是優點也是很大的缺點。優點是容易學習與使用,缺點是像開發者經常會因為賦值或傳值的類型錯誤,造成不如預期的結果。有些時候在使用框架或函數庫時,如果沒有仔細看文件,亦或是文件寫得不清不楚,也容易造成誤用的情況。

這個缺點在應用規模化時,會顯得更加嚴重。我們在開發團隊的協同時,一般都是用詳盡的文字說明,來降低這個問題的發生,但JS語言本身無法有效阻止這些問題。而且說明文件也需要花時間額外編寫,其他的開發者閱讀也需要花時間。在現今預先編譯器流行的年代,像TypeScript這樣的強(靜態)類的JavaScript超集語言就開始流行,用嚴格的角度,以JavaScript語言為基底,來重新打造另一套具有強(靜態)類型特性的語言,就如同Java或C#這些語言一樣,這也是為什麽TypeScript稱自己是企業級的開發JavaScript解決方案。

TypeScript自然有它的市場,但它有一些明顯的問題,首先是JavaScript開發者需要再進一步學習,內容不少,也有一定陡峭的學習曲線,不過這還算小事情。重大的事情是需要把已經在使用的應用代碼,都要整個改用TypeScript代碼語法,才能發揮完整的功用。這對很多已經有內部代碼庫的大型應用開發團隊而言,將會是個重大的決定,因為如果不往全面重構的路走,將無法發揮強(靜態)類型語言的最大效用。

所以許多現行的開源碼函數庫或框架,並不會直接使用TypeScript作為代碼的語言,另一方面當然因為是TypeScript並非普及到一定程度的語言,社群上有熱愛的粉絲也有不是那麽支持的反對者。當然,TypeScript也有它的優勢,自從TypeScript提出了DefinitelyTyped的解決方式之後,讓現有的函數庫能額外再定義出裏面使用的類型,這也是另一個可以與現有框架與庫相整合的方案,這讓許多函數庫與框架都提交定義檔案,提供了另一種選擇。另一個優勢是,TypeScript也是個活躍的開源碼項目,發展到現在也有一段時間,算是逐漸成熟的項目。它的背後有微軟公司的支持,在最近發布的知名的、全新打造過的Angular2框架中(由Google主導),也采用了TypeScript作為基礎的開發語言。

現在,Flow提供了另一個新的選項,它是一種強(靜態)類型的輔助檢查工具。Flow的功能是讓現有的JavaScript語法可以事先作類型的聲明(定義),在開發過程中進行自動檢查,當然在最後編譯時,一樣可以用babel工具來移除這些標記。

相較於TypeScript是另外重新制定一套語言,最後再經過編譯為JavaScript代碼來運行。Flow走的則是非強制與非侵入性的路線。Flow的優點是易學易用,它的學習曲線沒有TypeScript來得高,雖然內容也很多,但大概一天之內學個大概,就可以漸進式地開始使用。而且因為Flow從頭到尾只是個檢查工具,並不是新的程序語言或超集語言,所以它可以與各種現有的JavaScript代碼兼容,如果你哪天不想用了,就去除掉標記就是回到原來的代碼,沒什麽負擔。當然,Flow的功用可能無法像TypeScript這麽全面性,也不可能改變要作某些事情的語法結構。

redux-form支持基於Flow的靜態類型檢查

當你從redux-form庫中使用import語句導入組件或者函數時Flow能夠自動導入相應的類型。而且,你還可以把redux-form提供的所有props類型導入到你的組件中。

有關在JS項目下Flow的安裝,請參考文後的文檔,在此省略。如果你在配置文件.flowconfig中忽略node_modules文件夾的話,相應的類型不會導入,而且你還會接收到錯誤提示,如下所示:

import { Field, reduxForm } from ‘redux-form‘
^^^^^^^^^^^^ redux-form. Required module not found
因此,在你的文件.flowconfig中,請確保整個文件夾不被忽略:
...
[ignore]
<PROJECT_ROOT>/node_modules/editions # you can still selectively ignore packages that cause flow errors
[include]

有關Props類型的簡單使用舉例

下面的幾個例子展示了如何基於Flow在redux-form項目中把相應的類型支持註入到你的使用reduxForm()這個高階組件(HOC)封裝的表單組件中。

使用FormProps舉例

import type { FormProps } from ‘redux-form‘

type Props = {
  someCustomThing: string
} & FormProps
// ^^^^^^^^^^

class MyForm extends React.Component {
  props: Props

  render() {
    const { handleSubmit, someCustomThing } = this.props
    return <form onSubmit={handleSubmit}>// fields here</form>
  }
}

使用FieldProps舉例

import type { FieldProps } from ‘redux-form‘

const renderField = ({ input, meta, ...rest } : FieldProps) =>
//                                           ^^^^^^^^^^^^^
  <div>
    <input {...input} {...rest}/>
    {meta.touched && meta.error && <div>{meta.error}</div>}
  </div>

...

<Field name="myField" component={renderField}/>

使用FieldsProps

import type { FieldsProps } from ‘redux-form‘

const renderField = (fields : FieldsProps) =>
//                         ^^^^^^^^^^^^^^
  <div>
    {fields.map(({ input, meta, ...rest }) =>
      <div>
        <input {...input} {...rest}/>
        {meta.touched && meta.error && <div>{meta.error}</div>}
      </div>)
    }
  </div>

...

<Fields names={[ ‘firstField‘, ‘secondField‘ ]} component={renderFields}/>

使用FieldArrayProps舉例

import type { FieldArrayProps } from ‘redux-form‘

const renderFieldArray = ({ fields } : FieldArrayProps) =>
//                             ^^^^^^^^^^^^^^^^^^
  <ul>
    {fields.map((name, index, fields) => (
      <li key={index}>
        <Field
          name={`${name}.firstName`}
          type="text"
          component={renderField}
          label="First Name"/>
        <Field
          name={`${name}.lastName`}
          type="text"
          component={renderField}
          label="Last Name"/>
      </li>
    ))}
  </ul>

...

<FieldArray name="contacts" component={renderFieldArray}/>

小結

正如前面提及的,在小型JavaScript項目中,如果你有把握,可以省略使用Flow。盡管如此,但是事實證明,只要你選擇使用js開發,主動使用Flow將會為你帶來很多的驚喜——這遠大於你學習Flow的時間投入。在基於React的redux-form子項目開發中,上述結論也不例外。

參考資料

1.https://segmentfault.com/a/1190000010088546
2.https://redux-form.com/7.4.2/docs/flow.md/
3.https://flow.org/en/docs/usage/
4.https://segmentfault.com/a/1190000008088489
5.https://segmentfault.com/a/1190000010205508

redux-form(V7.4.2)筆記(三)之Flow簡介