Как стать автором
Обновить

Эффективная работа с формами с помощью react-redux-hook-form

Время на прочтение3 мин
Количество просмотров5.2K

Привет! Это моя первая статья на Хабре и в ней я хочу рассказать о, первой мной написанной, библиотеке для работы с формами. Но сперва, давайте поговорим о том, как должна выглядеть идеальная библиотека для работы с формами.

  1. Синтаксис будто создан для написания форм.

  2. Формы просто дебажить и, еще проще, облагать их тестами.

  3. Полная инкапсуляция логики конкретных инпутов.

  4. Компоненты инпутов должны быть реюзабельными.

  5. Конечная форма должна быть максимально абстрактной и легко читаемой.

А теперь, давайте посмотрим, как выглядит форма написанная с помощью 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 года. да и то треть из этого опыта это работа на бэке. Так что жду предложению по тому, как можно улучшить данную библиотеку :)

Теги:
Хабы:
Всего голосов 4: ↑2 и ↓2+3
Комментарии5

Публикации

Истории

Работа

Ближайшие события

7 – 8 ноября
Конференция byteoilgas_conf 2024
МоскваОнлайн
7 – 8 ноября
Конференция «Матемаркетинг»
МоскваОнлайн
15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
22 – 24 ноября
Хакатон «AgroCode Hack Genetics'24»
Онлайн
28 ноября
Конференция «TechRec: ITHR CAMPUS»
МоскваОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань