Пару лет назад я увидел на хабре статью про LIVR и с тех пор использую библиотеку на всех проектах. С переходом на React я адаптировал для валидации ее же, т.к. существующие решения не предлагали гибкости которой мне хотелось. Свое решение я уже использую на двух проектах и решил выложить в npm — может кому-то еще оно покажетсяя удобным.
Пакет называется react-livr-validation.
Пример базового использвания
import React from 'react';
import Validation, {DisabledOnErrors, ValidationInput} from 'react-livr-validation';
const schema = {
login: ['required', 'not_empty'],
password: ['required', 'not_empty']
};
const data = {
login: '',
password: ''
};
export default function() {
return (
<Validation
data={data}
schema={schema}
>
<form>
<ValidationInput name="login" >
<input name="login" />
</ValidationInput>
<ValidationInput name="password" >
<input name="password" type="password" />
</ValidationInput>
<DisabledOnErrors>
<input type="submit" />
</DisabledOnErrors>
</form>
</Validation>
);
}
Компонент принимает валидационную схему и первоначальные данные(если данные не валидны, кнопка submit сразу будет неактивна), так же можно передать custom rules и aliased rules
const customRules = {
alpha_chars: function() {
return function(value) {
if (typeof value === 'string') {
if (!/[a-z,A-Z]+/.test(value)) {
return 'WRONG_FORMAT';
}
}
};
}
};
const aliasedRules = [
{
name: 'strong_password',
rules: { min_length: 6 },
error: 'TOO_SHORT'
}
];
<Validation
data={data}
schema={schema}
rules={customRules}
aliasedRules={aliasedRules}
>
// ... form
</Validation>
Обертка ValidationInput добавляет в инпут свои обработчики событий, на которые будет происходить валидация. По умолчанию это события change, blur, keyup.
<ValidationInput name="password" valicateOnEvents={['change', 'blur', 'keyUp']} >
<input name="password" type="password" />
</ValidationInput>
Есть возможность реализовать свою обертку — пакет экпортит HOC, который прокидывает в пропсы api
// @flow
import React, {Component} from 'react'
import {ValidationComponent} from 'react-livr-validation'
import get from 'lodash/get'
import noop from 'lodash/noop'
import compose from 'ramda/src/compose'
import styled from 'styled-components'
type DataChunk = {
name: string,
value: any
}
type State = {
touched: boolean
}
type Props = {
// will be passed by HOC
setData: (data: DataChunk) => void,
getError: (name: string) => ?string,
getErrors: () => Object,
className: string, // for the error block
style: Object // for the error block
errorCodes: Object,
name: string,
field: string
}
class NestedError extends Component {
props: Props;
isTouched() {
const {children} = this.props;
return get(children, 'props.value')
}
state: State = {
touched: this.isTouched()
}
setTouched() {
this.setState({
touched: true
})
}
cloneElement() {
const {children} = this.props;
const onBlur = get(children, 'props.onBlur', noop);
return React.cloneElement(
children,
{
onBlur: compose(this.setTouched, onBlur)
}
)
}
render() {
const {touched} = this.state;
const {
children,
field,
name,
getError,
errorCodes,
style,
className
} = this.props;
const errors = getErrors();
const error = get(errors, `${field}`.${name});
return (
<div>
{touched ? children : this.cloneElement()}
{error &&
<Error
className={className}
style={style}
>
{errorCodes[error] || error}
</Error>
}
</div>
);
}
}
const Error = styled.div`
color: red;
`;
export default ValidationComponent(NestedError)
Автор: Дмитрий Николаев