嗯,可能也是最后一版。。。哈哈~~~只是写着玩
简化版的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,'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 <Component { ...props } />; } } 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 ( <div> <Form ref={instance=>{ this.instance=instance; }} initialValues={{ name: true }}/> <button style={{ marginLeft: "200px" }} onClick={this.onClick}>Values</button> </div> ) } }
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 ( <form onSubmit={handleSubmit(this.onSubmit)} style={{ marginLeft: "200px" }}> <label> name: <input type="checkBox" name="name" value="123" {...name}/> </label> <label> bbb <input type="text" name="bbb" {...bbb}/> </label> <button type="submit">submit</button> </form> ) } }
用法:
@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
中的数据