อีกสิ่งหนึ่งสำหรับผู้ที่ต้องการสร้างองค์ประกอบแบบฟอร์มที่ควบคุมโดยไม่ต้องใช้ห้องสมุดขนาดใหญ่
ReduxFormHelper - คลาส ES6 ขนาดเล็กน้อยกว่า 100 บรรทัด:
class ReduxFormHelper {
constructor(props = {}) {
let {formModel, onUpdateForm} = props
this.props = typeof formModel === 'object' &&
typeof onUpdateForm === 'function' && {formModel, onUpdateForm}
}
resetForm (defaults = {}) {
if (!this.props) return false
let {formModel, onUpdateForm} = this.props
let data = {}, errors = {_flag: false}
for (let name in formModel) {
data[name] = name in defaults? defaults[name] :
('default' in formModel[name]? formModel[name].default : '')
errors[name] = false
}
onUpdateForm(data, errors)
}
processField (event) {
if (!this.props || !event.target) return false
let {formModel, onUpdateForm} = this.props
let {name, value, error, within} = this._processField(event.target, formModel)
let data = {}, errors = {_flag: false}
if (name) {
value !== false && within && (data[name] = value)
errors[name] = error
}
onUpdateForm(data, errors)
return !error && data
}
processForm (event) {
if (!this.props || !event.target) return false
let form = event.target
if (!form || !form.elements) return false
let fields = form.elements
let {formModel, onUpdateForm} = this.props
let data = {}, errors = {}, ret = {}, flag = false
for (let n = fields.length, i = 0; i < n; i++) {
let {name, value, error, within} = this._processField(fields[i], formModel)
if (name) {
value !== false && within && (data[name] = value)
value !== false && !error && (ret[name] = value)
errors[name] = error
error && (flag = true)
}
}
errors._flag = flag
onUpdateForm(data, errors)
return !flag && ret
}
_processField (field, formModel) {
if (!field || !field.name || !('value' in field))
return {name: false, value: false, error: false, within: false}
let name = field.name
let value = field.value
if (!formModel || !formModel[name])
return {name, value, error: false, within: false}
let model = formModel[name]
if (model.required && value === '')
return {name, value, error: 'missing', within: true}
if (model.validate && value !== '') {
let fn = model.validate
if (typeof fn === 'function' && !fn(value))
return {name, value, error: 'invalid', within: true}
}
if (model.numeric && isNaN(value = Number(value)))
return {name, value: 0, error: 'invalid', within: true}
return {name, value, error: false, within: true}
}
}
มันไม่ทำงานทั้งหมดสำหรับคุณ อย่างไรก็ตามมันช่วยอำนวยความสะดวกในการสร้างการตรวจสอบความถูกต้องและการจัดการขององค์ประกอบแบบฟอร์มที่มีการควบคุม คุณสามารถคัดลอกและวางรหัสข้างต้นลงในโครงการของคุณหรือแทนรวมถึงห้องสมุดที่เกี่ยวข้อง - redux-form-helper
(plug!)
วิธีใช้
ขั้นตอนแรกคือการเพิ่มข้อมูลเฉพาะในสถานะ Redux ซึ่งจะแสดงสถานะของแบบฟอร์มของเรา ข้อมูลเหล่านี้จะรวมถึงค่าของเขตข้อมูลในปัจจุบันเช่นเดียวกับชุดของการตั้งค่าสถานะข้อผิดพลาดสำหรับแต่ละเขตข้อมูลในแบบฟอร์ม
สถานะของแบบฟอร์มอาจถูกเพิ่มลงในตัวลดที่มีอยู่หรือกำหนดไว้ในตัวลดที่แยกต่างหาก
นอกจากนี้ยังจำเป็นต้องกำหนดการดำเนินการเฉพาะที่เริ่มต้นการอัปเดตสถานะของฟอร์มรวมถึงผู้สร้างแอคชั่นที่เกี่ยวข้อง
ตัวอย่างการกระทำ :
export const FORM_UPDATE = 'FORM_UPDATE'
export const doFormUpdate = (data, errors) => {
return { type: FORM_UPDATE, data, errors }
}
...
ตัวอย่างการลด :
...
const initialState = {
formData: {
field1: '',
...
},
formErrors: {
},
...
}
export default function reducer (state = initialState, action) {
switch (action.type) {
case FORM_UPDATE:
return {
...ret,
formData: Object.assign({}, formData, action.data || {}),
formErrors: Object.assign({}, formErrors, action.errors || {})
}
...
}
}
ขั้นตอนที่สองและขั้นสุดท้ายคือการสร้างส่วนประกอบคอนเทนเนอร์สำหรับฟอร์มของเราและเชื่อมต่อกับส่วนที่เกี่ยวข้องของสถานะ Redux และการกระทำ
นอกจากนี้เราต้องกำหนดรูปแบบการระบุการตรวจสอบความถูกต้องของเขตข้อมูลแบบฟอร์ม ตอนนี้เราสร้างอินสแตนซ์ของReduxFormHelper
วัตถุในฐานะสมาชิกขององค์ประกอบและผ่านไปที่นั่นแบบจำลองรูปแบบของเราและการปรับปรุงการส่งกลับสถานะการโทรกลับของสถานะ
จากนั้นในrender()
วิธีการขององค์ประกอบเราจะต้องผูกแต่ละเขตข้อมูลonChange
และonSubmit
เหตุการณ์ของรูปแบบด้วยprocessField()
และprocessForm()
วิธีการตามลำดับเช่นเดียวกับการแสดงบล็อกข้อผิดพลาดสำหรับแต่ละเขตข้อมูลขึ้นอยู่กับธงข้อผิดพลาดแบบฟอร์มในรัฐ
ตัวอย่างด้านล่างใช้ CSS จากเฟรมเวิร์ก Bootstrap ของ Twitter
ตัวอย่างส่วนประกอบคอนเทนเนอร์ :
import React, {Component} from 'react';
import {connect} from 'react-redux'
import ReduxFormHelper from 'redux-form-helper'
class MyForm extends Component {
constructor(props) {
super(props);
this.helper = new ReduxFormHelper(props)
this.helper.resetForm();
}
onChange(e) {
this.helper.processField(e)
}
onSubmit(e) {
e.preventDefault()
let {onSubmitForm} = this.props
let ret = this.helper.processForm(e)
ret && onSubmitForm(ret)
}
render() {
let {formData, formErrors} = this.props
return (
<div>
{!!formErrors._flag &&
<div className="alert" role="alert">
Form has one or more errors.
</div>
}
<form onSubmit={this.onSubmit.bind(this)} >
<div className={'form-group' + (formErrors['field1']? ' has-error': '')}>
<label>Field 1 *</label>
<input type="text" name="field1" value={formData.field1} onChange={this.onChange.bind(this)} className="form-control" />
{!!formErrors['field1'] &&
<span className="help-block">
{formErrors['field1'] === 'invalid'? 'Must be a string of 2-50 characters' : 'Required field'}
</span>
}
</div>
...
<button type="submit" className="btn btn-default">Submit</button>
</form>
</div>
)
}
}
const formModel = {
field1: {
required: true,
validate: (value) => value.length >= 2 && value.length <= 50
},
...
}
function mapStateToProps (state) {
return {
formData: state.formData, formErrors: state.formErrors,
formModel
}
}
function mapDispatchToProps (dispatch) {
return {
onUpdateForm: (data, errors) => {
dispatch(doFormUpdate(data, errors))
},
onSubmitForm: (data) => {
// dispatch some action which somehow updates state with form data
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(MyForm)
การสาธิต
redux-forms
หรือเปล่า? ฉันสงสัยว่าขนาดของ