純粹使用react進行表單校驗:html
class MyForm extends React.Component{ constructor(props){ super(props) this.onAddrChange = this.onAddrChange.bind(this); this.state = { addr:"" } } onAddrChange(evt){
this.setState({ addr:evt.target.value }) } render(){ return ( <form>
<input type="text" value={this.state.addr} onChange={this.onAddrChange}/>
</form>
) } }
可見爲了維持雙向綁定,以及校驗信息。一個input至少須要3個以上的變量(value + change callback + verify message),表單比較大的話,代碼邏輯十分複雜。前端
redux-form-utils這個庫沒作好,內部報錯了用不了。直接使用redux-formreact
https://redux-form.com/6.6.3/examples/redux
最簡單的例子:api
import React from 'react'; import ReactDOM from 'react-dom'; import {createStore, combineReducers} from 'redux' import { Provider } from 'react-redux' import {reducer, Field, reduxForm} from "redux-form" const rootReducer = combineReducers({ form: reducer }); const store = createStore(rootReducer); class ContactForm extends React.Component{ handleSubmit(e){ console.log("submited") e.preventDefault() } render(){ return ( <form onSubmit={this.handleSubmit}>
<div>
<label htmlFor="email">Email</label>
<Field name="email" component="input" type="text" />
</div>
<button type="submit">Submit</button>
</form>
) } } ContactForm = reduxForm({ form: 'contact' })(ContactForm) ReactDOM.render( <Provider store={store}>
<ContactForm store={store}></ContactForm>
</Provider>,
document.getElementById('root') );
基本的使用流程:promise
理解以上的更新關係很重要:服務器
組件樹中的組件的渲染順序都是深度優先,即 全部的Field會被首先執行,內部執行的過程當中就把name值設置到store上了。框架
這個內置的組件用於加強咱們的input。以上的component屬性中使用的是input。其實也能夠傳遞一個自定義的組件:dom
function MyCs(props){ console.log(props) return <div></div> } <Field name="email" component={MyCs} type="text" x="123"/>
輸出的數據:異步
以上的Field標籤渲染出來的結果就是一個 <div></div>。可見,經過Field組件,咱們能夠封裝一些表單中的子組件。
input和meta中的屬性參考:https://redux-form.com/7.2.0/docs/api/field.md/#props
查看以上的關係圖能夠發現,onChange是定義在加強後的組件中的,在那裏能夠最先獲取到表單數據,也能夠把校驗相關的函數封裝進去。由於這個加強後的組件是經過reduxForm生成的,天然而然校驗相關的函數也應該經過reduxForm傳遞進去(經過一個配置對象傳入):
export default reduxForm({ form: 'syncValidation', validate, // <--- validation function given to redux-form
warn // <--- warning function given to redux-form
})(SyncValidationForm)
以上函數中能夠經過參數獲取到最新的表單數據,返回一個校驗信息對象,這個對象中映射了指定name的input與之校驗信息的對應關係。
使用的方式以下:
校驗函數(error|warning)返回 { age: "age is required" }
對於組件:<Field name="age" type="number" component={renderField} label="Age" /> 。在renderField這個組件內,能夠經過參數props.meta.error|warning獲取到 "age is required" 這個校驗信息,而後組件內把這個錯誤信息顯示出來便可。
error和warning函數的返回對象均可以用在Field所指定的組件內部,但他們的區別是什麼?只要error有值,則表單onSubmit就不會觸發,而warning不影響提交。
以上的校驗是針對整個表單的校驗,全部校驗邏輯集中在一個函數中。使用Field級別的校驗能夠把每種校驗類型拆分出來,針對Field可實現更加靈活的校驗控制。
const required = value => (value ? undefined : 'Required') const alphaNumeric = value => value && /[^a-zA-Z0-9 ]/i.test(value) ? 'Only alphanumeric characters' : undefined <Field name="username" type="text" component={renderField} label="Username" validate={[required, maxLength15, minLength2]} warn={alphaNumeric} />
返回undefined則表明校驗經過,返回的字符串和上面同樣,能夠在對應的Field指定的組件內經過props.meta.warning | error 獲取。
reduxForm加強表單的時候配置對象以下:
export default reduxForm({ form: 'asyncValidation', validate, asyncValidate, asyncBlurFields: ['username'] })(AsyncValidationForm)
asyncBlurFields:指定當哪些FieldonBlur的時候觸發異步校驗
asyncValidate:指定異步校驗的函數,在這個函數中返回一個promise,promise中若是拋出一個校驗信息對象,則表明校驗失敗
以上輸出前端的校驗,怎麼處理服務端的校驗信息呢?
在submit的回調函數中,返回一個promise,在這個promise中進行異步請求。這個promise被resolve的話則提交完成。若是內部拋出SubmissionError錯誤,則表明校驗失敗
throw new SubmissionError({ password: 'Wrong password', _error: 'Login failed!' })
被包裹的對象和以前校驗函數返回的對象用法一致。
把reduxForm加強後的表單,進行connect;而表單中Field字段,默認讀取props.initialValues.xxname的值,因此簡單的同步初始化方式是:
const data = { firstName: 'Jane', lastName: 'Doe', } InitializeFromStateForm = connect( state => ({ initialValues: data }) )(InitializeFromStateForm)
由於connect的做用是實現自動關聯。因此只要在異步請求後,調用dispatch,把異步數據發送給reducer,上面就不用直接讀取data,而是從state中讀取異步數據,界面能自動刷新,這樣就實現了異步的狀態初始化,簡單的例子能夠查看 這裏
注意:由於props會層層傳遞,因此,以上connect中mapStateToProps(state)和mapDispatchProps(dispatch)返回的值也能夠在表單中經過props.xxx來使用,針對這一點,容許咱們在表單中使用一些表單值之外的變量
假如我有一個需求,當點擊了checkBox,則把一個表單模塊顯示出來。由於表單項的值都交由框架進行處理,因此沒辦法在jsx中直接訪問。但經過connect映射出來的props能夠在jsx中直接使用,咱們只須要在映射的時候獲取到表單項的值,而後對這些值進行映射,把新的值返回。這樣就能夠在jsx中訪問了。經過redux-form提供的selector能夠獲取到表單項的值。
用於相同輸入組件的動態添加和刪除。
對用戶輸入的值進行格式化,格式化後的值能夠在onSubmit中獲取,以及會顯示到界面上。使用方式和Field級別的校驗相似,在Field上添加一個字段,指定一個格式化函數便可。
將程序的狀態所有設置爲不可變,能夠把從redux-form獲取的值所有改爲從redux-form/immutable中獲取,校驗以及提交的時候,獲取值從values.xxx 更改成 values.Get("xxx") 便可。
把表單拆分紅多個部分,每一個部分放在不一樣的頁面中顯示,每一個頁面填寫完,再跳轉到下一個頁面繼續填寫,相似於嚮導頁。
以上說切換頁面,實際是在切換組件的顯示,每一個組件表明一個表單頁,內部有一個完成的表單,但在redux-from加強的時候必須指定這多個表單的具備相同的form值,並且unmount的時候不銷燬。