Привет! Это моя первая статья на Хабре и в ней я хочу рассказать о, первой мной написанной, библиотеке для работы с формами. Но сперва, давайте поговорим о том, как должна выглядеть идеальная библиотека для работы с формами.
Синтаксис будто создан для написания форм.
Формы просто дебажить и, еще проще, облагать их тестами.
Полная инкапсуляция логики конкретных инпутов.
Компоненты инпут��в должны быть реюзабельными.
Конечная форма должна быть максимально абстрактной и легко читаемой.
А теперь, давайте посмотрим, как выглядит форма написанная с помощью react-redux-hook-form.
export const Login:FC = memo( () => {
const form = useForm({name: 'login'})
return (
<WrapperForm form={form} onSubmit={(data:ILogin) => {User.options.login(data)}}>
<InputTitleStyled>Номер телефона</InputTitleStyled>
<PhoneInput name={'username'} required/>
<InputTitleStyled>Пароль</InputTitleStyled>
<PasswordInput name={'password'} required/>
<SubmitButton text={'Авторизироваться'}/>
</WrapperForm>
)
})Здесь мы используем хук useForm и обертку для формы WrapperForm.
useForm - хук для инициализации формы, принимает name и возвращает объект с методами для работы с формой. form.reset, form.changeDataField, form.changeIsValidateField, form.changeMessageErrorField, form.useFieldSelector. Полагаю, не имеет смысла описывать принцип работы каждого метода.
WrapperForm - обертка формы в которую обязательно должна быть обернута форма. Принимает параметры: onChange, initialValue, onSubmit.
Теперь давайте посмотрим, как создаются инпуты.
interface IEmail {
name: string;
required?: boolean;
}
export const EmailInput: FC<IEmail> = (props) => {
const {useData, useIsValidate, useIsTouch, useMessageError} = useField({
name: props.name,
isRequired: props.required,
validateFunction: (value:string) => validate(value).string().max(30).email(),
})
const [data, changeData] = useData()
const [isValidate, ] = useIsValidate()
const [isTouch, ] = useIsTouch()
const [messageError, ] = useMessageError()
return (
<>
<EmailInputStyled
type={"email"}
value={data}
onChange={(e:any)=> {changeData(e.target.value)}}
isValidate={isValidate || !isTouch}
id={props.name}
/>
{!isValidate && isTouch &&
<ErrorTitleStyled className={'error'}>
{messageError}
</ErrorTitleStyled>
}
</>
)
};Здесь мы используем useField. useField - инициализирует поле и из него достаются хуки для работы с полем. useData, useIsValidate, useIsTouch, useMessageError, работают по принципу useState. Validate/IsTouch/MessageError - автоматически обрабатываются, но если вы хотите самостоятельно обрабатывать данные поля, библиотека позволит вам это сделать. Для того, чтобы отменить автоматическую обработку, необходимо в useField передать isDisableAuto: true.
Параметры useField: name, initialValue, isRequired, isDisableAuto, messageError, isTouch, isValidate, validateFunction.
name: название поля. Все поля должны быть уникальными.
initialValue: стандартное значение. Стоит использовать для того, чтобы явно указать, в каком формате будут храниться данные в данном инпуте. Перебивается initialValues с формы.
Теперь давайте посмотрим, как создать кнопку, для данной формы.
interface ISubmitButton {
text: string;
className?: string;
}
export const SubmitButton: FC<ISubmitButton> = (props) => {
const formName = useContext(formNameContext)
const isValidForm = useIsValidForm(formName)
const onSubmit = useContext(onSubmitContext)
const onClick = () => {
if(isValidForm){
onSubmitForm(formName, onSubmit)
}
}
return (
<SubmitButtonStyled className={props.className} isValidForm={isValidForm} onClick={onClick}>
{props.text}
</SubmitButtonStyled>
)
};В данном примере мы достаем из контекста formName и onSubmit.
Также мы используем useIsValidateForm хук, в которым передаем имя формы.
Так-как мы используем redux. То мы можем использовать данные формы в других местах.
Например:
const search = useFieldSelector({formName: 'searchForm', fieldName: 'search'})Подключение react-redux-hook-form.
Сперва установим: npm i react-redux-hook-form.
Затем надо модифицировать стор.
1) Подключим formControllerReducer.
import { formControllerReducer } from 'react-redux-hook-form';
const combinedReducer = combineReducers({
formController: formControllerReducer, // подключение formControllerReducer
user: userReducer,
contact: contactReducer,
});2) Запишем функцию getState в window.
window.getState = () => store.getState()В общем-то это все что нужно знать для того чтобы использовать react-redux-hook-form.
Так как мы используем redux, мы можем дебажить форму через redux-devtools(расширения гугл хрома).
Думаю, еще стоит уделить пару строчек себе. У меня не так много коммерческого опыта, всего лишь 1.5 года. да и то треть из этого опыта это работа на бэке. Так что жду предложению по тому, как можно улучшить данную библиотеку :)
