redux-form(V7.4.2)筆記(四)SelectingFormValuesForm實例解析

本文將繼續我學習redux-form的總結部分,在這一部分中,我將對官方示例SelectingFormValuesForm給出簡要解析,不當處還希望同志們批評指正。

示例SelectingFormValuesForm簡介

本示例原意重在介紹formValueSelector這個redux-form API的用法的。官文上說,在我們的表單中有時候想訪問表單中另外一些字段值時可以使用這個API。不過,要使用這個formValueSelector API,我們需要使用connect方法把表單中的有關字段值直接連接到Redux store上。

但是,官方還提出警告:要小心使用上面這個API,因爲每當表單中有關字段值改變時整個表單都會重新渲染,從而影響系統性能。

示例中有關代碼分析

在redux-demo的大多數示例中,關鍵代碼都在於表單(也是react-redux容器)
定義部分。下面給出表單SelectingFormValuesForm的定義代碼:

SelectingFormValuesForm.js
import React from 'react'
import { connect } from 'react-redux'
import { Field, reduxForm, formValueSelector } from 'redux-form'

let SelectingFormValuesForm = props => {
  const {
    favoriteColorValue,
    fullName,
    handleSubmit,
    hasEmailValue,
    pristine,
    reset,
    submitting
  } = props
  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label>First Name</label>
        <div>
          <Field
            name="firstName"
            component="input"
            type="text"
            placeholder="First Name"
          />
        </div>
      </div>
      <div>
        <label>Last Name</label>
        <div>
          <Field
            name="lastName"
            component="input"
            type="text"
            placeholder="Last Name"
          />
        </div>
      </div>
      <div>
        <label htmlFor="hasEmail">Has Email?</label>
        <div>
          <Field
            name="hasEmail"
            id="hasEmail"
            component="input"
            type="checkbox"
          />
        </div>
      </div>
      {hasEmailValue && (
        <div>
          <label>Email</label>
          <div>
            <Field
              name="email"
              component="input"
              type="email"
              placeholder="Email"
            />
          </div>
        </div>
      )}
      <div>
        <label>Favorite Color</label>
        <div>
          <Field name="favoriteColor" component="select">
            <option />
            <option value="#ff0000">Red</option>
            <option value="#00ff00">Green</option>
            <option value="#0000ff">Blue</option>
          </Field>
        </div>
      </div>
      {favoriteColorValue && (
        <div
          style={{
            height: 80,
            width: 200,
            margin: '10px auto',
            backgroundColor: favoriteColorValue
          }}
        />
      )}
      <div>
        <button type="submit" disabled={pristine || submitting}>
          Submit {fullName}
        </button>
        <button type="button" disabled={pristine || submitting} onClick={reset}>
          Clear Values
        </button>
      </div>
    </form>
  )
}

// The order of the decoration does not matter.

// Decorate with redux-form
SelectingFormValuesForm = reduxForm({
  form: 'selectingFormValues' // a unique identifier for this form
})(SelectingFormValuesForm)

// Decorate with connect to read form values
const selector = formValueSelector('selectingFormValues') // <-- same as form name
SelectingFormValuesForm = connect(state => {
  // can select values individually
  const hasEmailValue = selector(state, 'hasEmail')
  const favoriteColorValue = selector(state, 'favoriteColor')
  // or together as a group
  const { firstName, lastName } = selector(state, 'firstName', 'lastName')
  return {
    hasEmailValue,
    favoriteColorValue,
    fullName: `${firstName || ''} ${lastName || ''}`
  }
})(SelectingFormValuesForm)

export default SelectingFormValuesForm

上面代碼的關鍵點並不多。第一,注意import語句導入的connect方法,還有reduxForm和formValueSelector兩個方法的導入。

第二,接下來通過“let SelectingFormValuesForm=props=>{...}”語句定義表單SelectingFormValuesForm。注意它的剪頭函數的參數props中除了系統內置的屬性和方法定義外,還加入了定製的三個屬性(vavoriateColorValue,fullName和hasEmailValue)的定義。

API函數的使用

formValueSelector API的直接使用,主要體現在如下幾句代碼中:

// Decorate with connect to read form values
const selector = formValueSelector('selectingFormValues') // <-- same as form name
SelectingFormValuesForm = connect(state => {
  // can select values individually
  const hasEmailValue = selector(state, 'hasEmail')
  const favoriteColorValue = selector(state, 'favoriteColor')
  // or together as a group
  const { firstName, lastName } = selector(state, 'firstName', 'lastName')
  return {
    hasEmailValue,
    favoriteColorValue,
    fullName: `${firstName || ''} ${lastName || ''}`
  }
})(SelectingFormValuesForm)

易見,上面代碼中第一行創建了一個selector函數,這是通過調用API formValueSelector實現的,傳遞的參數是經過上面reduxForm封裝的容器表單SelectingFormValuesForm(注意,上面爲了偷懶,創建表單的變量名與由reduxForm方法返回的表單包裝以後的對象名是一樣的——這是經包裝以後的對象,實際上也是一個容器組件)。觀察源碼的話,你會注意到reduxForm方法內部重點調用了connect方法。
有關connect方法的作用,文後的參考中已作了詳細的分析,主要有兩點:
(1)此方法的作用在把React組件與Redux store連接到一起。
(2)此方法沒有修改傳入的React組件,而返回一個新的已經與Redux store連接的組件。

接下來再往下看,上面代碼中接着顯式調用connect方法,此方法的第一個參數通常命名爲mapStateToPros,意即把系統Store中的state轉換成各組件能夠訪問的props。在上面代碼中,通過調用了前面剛剛創建的selector函數(兩個參數含義明顯,略述),得到state中存儲的對應內容的一個副本。特別注意下面一句:

const { firstName, lastName } = selector(state, 'firstName', 'lastName')

這裏通過ES6的解構賦值,一次性取得一組值。最後,此函數(connect的第一個參數)返回一個新的對象,注意到對象的前兩個鍵值與鍵重名(ES6特性),第三個鍵則是一個新生成的鍵名。

可以看出,上面return語句返回的對象的各個屬性正對應於上面表單組件定義時props提供的幾個自定製屬性。這幾個數據是怎麼告訴給表單組件的呢?這要歸功於connect()方法。

補充

connect()方法是react-redux庫的核心方法之一,典型使用在定義包括上面的表單組件在內的容器組件的模塊中,而且可以多次嵌套式地使用,具體情形則根據需要而定。

小結

總起來講,是否使用本文提供的API formValueSelector,請謹記本文前提加粗的官方提醒的一句,不是非用不可,而是用巧了可以簡單編碼,在多表單多字段情況下用不好則導致影響系統性能!

參考資料

1.http://taobaofed.org/blog/2016/08/18/react-redux-connect/
2.https://www.jianshu.com/p/9873d4ccb891
3.https://github.com/lipeishang/react-redux-connect-demo/blob/master/public/src/containers/App.js
4.https://segmentfault.com/a/1190000010416732
5.https://redux-form.com/7.4.2/docs/gettingstarted.md/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章