Büyük boyutlu kitaplık kullanmadan tamamen kontrollü form bileşeni oluşturmak isteyenler için başka bir şey.
ReduxFormHelper - küçük bir ES6 sınıfı, 100 satırdan az:
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}
}
}
Senin için tüm işi yapmıyor. Bununla birlikte, kontrollü bir form bileşeninin oluşturulmasını, doğrulanmasını ve işlenmesini kolaylaştırır. Yukarıdaki kodu kopyalayıp projenize yapıştırabilir veya bunun yerine ilgili kitaplığı ekleyebilirsiniz - redux-form-helper
(fiş!).
Nasıl kullanılır
İlk adım, formumuzun durumunu temsil edecek olan Redux durumuna belirli veriler eklemektir. Bu veriler, formdaki her alan için geçerli alan değerlerini ve hata bayrakları kümesini içerecektir.
Form durumu, mevcut bir indirgeyiciye eklenebilir veya ayrı bir indirgeyicide tanımlanabilir.
Ayrıca, form durumunun güncellemesini başlatan belirli eylemin yanı sıra ilgili eylem oluşturucunun tanımlanması gerekir.
Eylem örneği :
export const FORM_UPDATE = 'FORM_UPDATE'
export const doFormUpdate = (data, errors) => {
return { type: FORM_UPDATE, data, errors }
}
...
Redüktör örneği :
...
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 || {})
}
...
}
}
İkinci ve son adım, formumuz için bir konteyner bileşeni oluşturmak ve onu Redux durumunun ve eylemlerinin ilgili bölümlerine bağlamaktır.
Ayrıca form alanlarının geçerliliğini belirleyen bir form modeli tanımlamamız gerekir. Şimdi ReduxFormHelper
nesneyi bileşenin bir üyesi olarak başlatıyoruz ve oraya form modelimizi ve form durumunun geri arama gönderme güncellemesini iletiyoruz.
Daha sonra, bileşenin render()
yönteminde, her alanın onChange
ve formun onSubmit
olaylarını sırasıyla processField()
ve processForm()
yöntemleriyle bağlamamız ve durumdaki form hata bayraklarına bağlı olarak her alan için hata bloklarını görüntülememiz gerekir.
Aşağıdaki örnek, Twitter Bootstrap çerçevesinden CSS kullanır.
Konteyner Bileşeni örneği :
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)
gösteri
redux-forms
musun? Tepki formlarına kıyasla bu şablonun nasıl ölçeklendiğini merak ediyorum