嗯,可能也是最后一版。。。哈哈~~~只是写着玩
简化版的redux-form
,只是觉得不需要redux-form
那么复杂的功能,也不想要和redux
关联,而且希望有一个简单管理form
的东西,所以就写了一个。肯定有很多不足,比如checkbox/radio group
怎么管理。。。没有解决。。。
import React from 'react';export default function reactForm(options){ const { fields=[], initialValues={}, validate, validateOnBlur, withRef } = options; return (Component)=>{ class Form extends React.Component { constructor(props) { super(props); this.initialValues = { ...initialValues, ...props.initialValues }; this.state = this.getInitialFields(); this.touchedKeys = {}; } componentWillReceiveProps(nextProps){ if(this.props.initialValues != nextProps.initialValues) { this.initialValues = { ...initialValues, ...nextProps.initialValues }; this.resetForm(); } } getInitialFields = ()=>{ return fields.reduce((prev, key)=>{ prev[key] = typeof this.initialValues[key] == "undefined" ? undefined : this.initialValues[key]; return prev; }, {}) } resetForm = ()=>{ this.setState(this.getInitialFields()); } setInstance = (instance)=>{ this.instance = instance; } getInstance = ()=>{ if(withRef) return this.instance; console.error("Can not get instance when withRef is false"); } getValues = ()=>{ return fields.reduce((prev, key)=>{ prev[key] = this.state[key]; return prev; }, {}); } getTouchedValues = ()=>{ let result = {}; for(let key in this.touchedKeys) { if(this.touchedKeys.hasOwnProperty(key)){ result[key] = this.state[key]; } } return result; } onFieldChange = (e, key)=>{ let value = ['radio', 'checkbox'].includes(e.target.type) ? e.target.checked : e.target.value; console.log(`trigger field change with ${key} ${value}`); this.setState({ [key]: value }, ()=>{ this.touchedKeys[key] = true; }); validate && validate(key, value); } onFieldBlur = (e, key)=>{ let value = ['radio', 'checkbox'].includes(e.target.type) ? e.target.checked : e.target.value; validateOnBlur(key, value); } handleSubmit = (fn)=>{ if(typeof fn == "function") { return (e)=>{ e.preventDefault(); e.stopPropagation(); fn(this.getValues()); } } else { fn.preventDefault(); fn.stopPropagation(); } } buildFields = ()=>{ return fields.reduce((prev, key)=>{ let value = this.state[key]; let field = { onChange: (e)=>{ this.onFieldChange(e, key) } }; if(typeof value === "boolean") field.checked = value; else field.value = value; if(validateOnBlur) field.onBlur = (e)=>{ this.onFieldBlur(e, key) }; prev[key] = field; return prev; }, {}) } buildProps = (props)=>{ let _props = { ...props }; _props.fields = this.buildFields(); _props.handleSubmit = this.handleSubmit; _props.getValues = this.getValues; _props.getTouchedValues = this.getTouchedValues; _props.resetForm = this.resetForm; if(withRef) { _props.ref = this.setInstance; } return _props; } render(){ let props = this.buildProps(this.props); return; } } return Form; }}
用例:
index.js
import React from 'react';import Form from './form';export default class FormApp extends React.Component { constructor(props) { super(props); } onClick = ()=>{ console.log(this.instance.getTouchedValues()); } render(){ return () }}
form.js
import React from 'react';import reactForm from 'components/react-form';function validate(key, value){ console.log(`validateOnBlur ${key} ${value}`);}@reactForm({ fields: ['name', 'bbb'], withRef: true, initialValues: { bbb: "bbbbbb" }, validateOnBlur: validate })export default class Form extends React.Component { constructor(props) { super(props); } onSubmit = (values)=>{ console.log(values); let { getTouchedValues } = this.props; console.log(getTouchedValues()); this.props.resetForm(); } render(){ let { fields: { name, bbb }, handleSubmit } = this.props; return () }}
用法:
@reactForm(options)
options: { fields: ["field1", "field2", "field3", "checkbox"...], // names of fields initialValues: { "field1":"value1", "field2":"value2", "checkbox":true }, // the initial values of fields validate: fn, // the function will be called when onChange validateOnBlur: fn, // the function will be called when onBlur withRef: false // when this is true, you can get the inner component by using getInstance}
Component
接受一个initialValues
参数。和上面的initialValues
作用一样,相同的key
会覆盖option.initialValues
中的值
API
handleSubmit
, 写在form
的onSubmit
事件中。
onSubmit={handleSumit}
或者onSubmit={handleSubmit(fn)}
,fn
会在form
提交的时候调用,形参为form
中的数据
fields
,和redux-form
一样。参考上面的例子getValues
获取所有的数据getTouchedValues
获取所有改变过(onChange)的数据