В первой части (Валидация форм 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, я её буду дописывать.
Если найдёте ошибки или есть предложения по улучшению пишите на почту буду дорабатывать, улучшать.
В комментариях к предыдущей статье было написано что есть другие хорошие библиотеки, да это так, но я считаю, что это не повод не писать свои решения, дорабатывать и улучшать их, когда есть желание написать.