В первой части (Валидация форм React. Часть 1) я описал, как можно работать с react-validate-form, теперь буду улучшать код. Вынесем в отдельный блок поле инпут, подсказки и ошибки. И подключим redux.
Если у вас библиотека не установлена, то её можно скачать git@github.com:tramak/react-validation-boo.git
А если вы устанавливали через npm install react-validation-boo, то обновите до последней версии, на момент публикации это 2.2.4.
Давайте теперь создадим компоненты InputBlock, InputCheckboxBlock, InputRadioGroupBlock, TextareaBlock, SelectBlock.
Обычно есть несколько дизайнов отображение форм. Создадим папку form в ней default это наш дизайн по умолчанию и в нём будем создавать компоненты.
Напишем блок для Select так чтобы опции можно было передавать не только через теги option, а ещё через массив.
Осталось реализовать компонент InputRadioGroupBlock, мы будем его реализовывать не на базе существующих, а с нуля. Компонент Form библиотеки react-validation-boo ищет среди своих потомков элементы с полем name и в них через props передаёт объект vBoo в этом объекте и находятся все необходимые методы для работы с валидацией компонента. Для начала напишем как мы будем использовать компонент.
Всё это описано в документации на github, я её буду дописывать.
Если найдёте ошибки или есть предложения по улучшению пишите на почту буду дорабатывать, улучшать.
В комментариях к предыдущей статье было написано что есть другие хорошие библиотеки, да это так, но я считаю, что это не повод не писать свои решения, дорабатывать и улучшать их, когда есть желание написать.
import React, {Component} from 'react'; import {connect as vBooConnect} from 'react-validation-boo'; import {connect as reduxConnect} from 'react-redux'; import {InputBlock, InputCheckboxBlock, InputRadioGroupBlock, TextareaBlock, SelectBlock} from '../form/default'; class MyForm extends Component { constructor() { super(); this.genderOptions = [ {value: '', label: 'Ваш пол?'}, {value: 1, label: 'Мужской'}, {value: 2, label: 'Женский'} ]; this.familyRadioList = [ {value: 1, label: 'холост'}, {value: 2, label: 'сожительство'}, {value: 3, label: 'брак'} ]; } componentWillMount() { this.props.vBoo.subscribe('change:input', this.props.onChangeVBooInput); this.props.vBoo.subscribe('valid:form', this.props.onChangeVBooValid); } render() { let s = this.props.myStore.inputs; return <Form connect={this.props.vBoo.connect}> <InputBlock name="name" value={s.name} /> <InputBlock name="email" value={s.email} /> <SelectBlock name="gender" options={this.genderOptions} value={s.gender} /> <InputRadioGroupBlock name="familyStatus" items={this.familyRadioList} value={s.familyStatus} /> <TextareaBlock name="comment" value={s.comment} /> <InputCheckboxBlock name="addition" value="yes" checked={s.addition==='yes'} /> <button onClick={this.sendForm}> {this.props.vBoo.isValid() ? 'Можно отправлять': 'Будьте внимательны!!!'} </button> </Form> } } export default reduxConnect( store => ({ myStore: { // для наглядности isValid: false, inputs: { email: 'test@mail.ru', gender: 0, familyStatus: 1 } } }), dispatch => ({ onChangeVBooInput: (input) => {...}, onChangeVBooValid: (isValid) => {...} }) )(vBooConnect({ rules: () => ([...]), labels: () => ({...}), })(MyForm));
Если у вас библиотека не установлена, то её можно скачать git@github.com:tramak/react-validation-boo.git
А если вы устанавливали через npm install react-validation-boo, то обновите до последней версии, на момент публикации это 2.2.4.
Давайте теперь создадим компоненты InputBlock, InputCheckboxBlock, InputRadioGroupBlock, TextareaBlock, SelectBlock.
Обычно есть несколько дизайнов отображение форм. Создадим папку form в ней default это наш дизайн по умолчанию и в нём будем создавать компоненты.
import React from 'react'; import {Input} from 'react-validation-boo'; class InputBlock extends Input { getError = () => { return this.props.vBoo.hasError() ? <div className="error">{this.props.vBoo.getError()}</div> : ''; }; render() { return ( <div> <label>{this.props.vBoo.getLabel()}:</label> <input {...this.props} onChange={this.change} onBlur={this.blur} /> {this.getError()} </div> ); } } export default InputBlock;
import React from 'react'; import {InputCheckbox} from 'react-validation-boo'; export default class InputCheckboxBlock extends InputCheckbox { getError = () => { return this.props.vBoo.hasError() ? <div className="error">{this.props.vBoo.getError()}</div> : ''; }; render() { return ( <div> <label>{this.props.vBoo.getLabel()}:</label> <input {...this.props} type="checkbox" onChange={this.change} /> {this.getError()} </div> ); } }
import React from 'react'; import {Textarea} from 'react-validation-boo'; export default class TextareaBlock extends Textarea { getError = () => { return this.props.vBoo.hasError() ? <div className="error">{this.props.vBoo.getError()}</div> : ''; }; render() { return ( <div> <label>{this.props.vBoo.getLabel()}:</label> <textarea {...this.props} onChange={this.change} onBlur={this.blur} /> {this.getError()} </div> ); } }
Напишем блок для Select так чтобы опции можно было передавать не только через теги option, а ещё через массив.
let genderOptions = [ {value: '', label: 'Ваш пол?'}, {value: 1, label: 'Мужской'}, {value: 2, label: 'Женский'} ]; <SelectBlock name="gender" options={genderOptions} /> <SelectBlock name="gender"> <option value="">Ваш пол</option> <option value="1">Мужской</option> <option value="2">Женский</option> </SelectBlock>
import React from 'react'; import {Select} from '../../../react-validation-boo/react-validation-boo/src/main'; export default class SelectBlock extends Select { componentWillMount() { this.children = this.props.options ? this.__getOptions(): this.props.children; } componentWillReceiveProps(nextProps) { let value = nextProps.value; if(this.props.value !== value) { this.props.vBoo.change(value); } } __getOptions() { return this.props.options.map((item) => { return <option value={item.value} disabled={item.disabled}>{item.label}</option>; }); } getError = () => { return this.props.vBoo.hasError() ? <div className="error">{this.props.vBoo.getError()}</div> : ''; }; render() { return ( <div> <label>{this.props.vBoo.getLabel()}:</label> <select {...this.props} onChange={this.change}> {this.children} </select> {this.getError()} </div> ); } }
Осталось реализовать компонент InputRadioGroupBlock, мы будем его реализовывать не на базе существующих, а с нуля. Компонент Form библиотеки react-validation-boo ищет среди своих потомков элементы с полем name и в них через props передаёт объект vBoo в этом объекте и находятся все необходимые методы для работы с валидацией компонента. Для начала напишем как мы будем использовать компонент.
let familyRadioList = [ {value: 1, label: 'холост'}, {value: 2, label: 'сожительство'}, {value: 3, label: 'брак'} ]; <InputRadioGroupBlock name="familyStatus" items={familyRadioList} />
import React, {Component} from 'react'; export default class InputRadioGroupBlock extends Component { state = { value: '' }; componentWillMount() { this.setState({value: this.props.value}); } componentDidMount() { this.props.vBoo.mount(this.state.value); } componentWillUnmount() { this.props.vBoo.unMount(); } componentWillReceiveProps(nextProps) { let value = nextProps.value; if(this.props.value !== nextProps.value) { this.props.vBoo.change(value); this.setState({value}); } } getOptions() { return this.props.items.map(item => { let checked = (this.state.value||'').toString()===(item.value||'').toString(); return <div key={item.value}> <input type="radio" name={this.props.name} value={item.value} checked={checked} onChange={this.change} /> <label>{item.label}</label> </div>; }); } change = (event) => { let value = event.target.value; this.props.onChange && this.props.onChange(event); this.props.vBoo.change(value); this.setState({value}); }; getError = () => { return this.props.vBoo.hasError() ? <div className="error">{this.props.vBoo.getError()}</div> : ''; }; render() { return ( <div> <div>{this.props.vBoo.getLabel()}:</div> {this.getOptions()} {this.getError()} </div> ); } }
Всё это описано в документации на github, я её буду дописывать.
Если найдёте ошибки или есть предложения по улучшению пишите на почту буду дорабатывать, улучшать.
В комментариях к предыдущей статье было написано что есть другие хорошие библиотеки, да это так, но я считаю, что это не повод не писать свои решения, дорабатывать и улучшать их, когда есть желание написать.
