Текстовые поля формы Formik - PullRequest
0 голосов
/ 28 марта 2020

Я использую текстовые поля пользовательского интерфейса и проверяю их с помощью Formik. Вместо того, чтобы печатать все несколько раз, я хочу отобразить элементы, но не могу этого сделать.

return (
    <div>
      <Formik
        initialValues={{ email: '' }}
        onSubmit={(values, actions) => {
          setTimeout(() => {
            alert(JSON.stringify(values, null, 2));
            actions.setSubmitting(false);
          }, 1000);
        }}
        validationSchema={schema}>
        {props => {
          const {
            values: { email },
            errors,
            touched,
            handleChange,
            isValid,
            setFieldTouched,
          } = props;
          const change = (name: string, e: FormEvent) => {
            e.persist();
            handleChange(e);
            setFieldTouched(name, true, false);
          };
          return (
            <div className="main-content">
              <form
                style={{ width: '100%' }}
                onSubmit={e => {
                  e.preventDefault();
                  submitForm(email);
                }}>
                <div>
                  <TextField
                    variant="outlined"
                    margin="normal"
                    id="email"
                    name="email"
                    helperText={touched.email ? errors.email : ''}
                    error={touched.email && Boolean(errors.email)}
                    label="Email"
                    value={email}
                    onChange={change.bind(null, 'email')}
                  />

{/* {[{ variant:"outlined", margin:"normal", id:"email", name:"email", label: "Email", value: email, onChange:{change.bind(null, 'email')}
          ].map((item, index) => (
            <TextField></TextField>
          ))} */}

                  <br></br>
                  <CustomButton
                    text={'Remove User'}
                  />
                </div>
              </form>
            </div>
          );
        }}
      </Formik>
    </div>
  );

В настоящее время в закомментированной части я получаю сообщения об ошибках change.bind, которые (property) change: (name: string, e: React.FormEvent<Element>) => void ',' expected.ts(1005)

Аналогично, если я пытаюсь добавить helperText:{touched.email ? errors.email : ''} в список параметров, которые должны быть сопоставленный с текстовым полем, я получаю это:

(property) touched: FormikTouched<{
    email: string;
}>
',' expected.ts(1005)

на touched.email. То же самое касается, когда я пытаюсь использовать errors.

(property) touched: FormikTouched<{
    email: string;
}>
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'FormikTouched<{ email: string; }>'.
  No index signature with a parameter of type 'string' was found on type 'FormikTouched<{ email: string; }>'.ts(7053)

1 Ответ

1 голос
/ 08 апреля 2020

Спасибо за песочницу.

На основе вашей песочницы мне удалось выполнить итерации полей с помощью функции map.

Сначала разделите уникальные реквизиты поля

  1. Реквизиты, принадлежащие входу, например name id label et c.
  2. Реквизит, который принадлежит компоненту, например variant margin handlers и c.

В итоге вы получите 2 объекта.

(1) Тот, который должен быть абстрактным для компонента и сохранен в отдельном файле, вы можете использовать поля в другом компоненте позже.

Здесь, поскольку вы используете formik и вам нужен ссылочный ключ для formik, я добавил formikRef в объект.

const fileds = [
  {
    id: "email",
    name: "email",
    formikRef: "email",
    label: "Email"
  },

  {
    id: "name",
    name: "name",
    formikRef: "name",
    label: "Name"
  }
];

(2) Второй объект, который должен храниться в компоненте, поскольку он разрешает <TextField/> реквизиты

Я обычно заключаю их в хук useMemo, поэтому его не нужно повторно объявлять, если объекты зависимостей не изменены. Это только для производительности, вы также можете использовать прямой объект

const defaultProps = React.useMemo(() => ({
    textField: {
      variant: 'outlined',
      margin: 'normal',
      onChange: props => {
        formik.handleChange(props);
        formik.handleBlur(props);
      },
      onBlur: formik.handleBlur
    }
  }),
  [formik]
);

//without useMemo

const defaultProps = {
  textField: {
    variant: 'outlined',
    margin: 'normal',
    onChange: props => {
      formik.handleChange(props);
      formik.handleBlur(props);
    },
    onBlur: formik.handleBlur
  }
}

Последний шаг - отобразить реквизиты в рендере

{
  fileds.map(({ formikRef, ...input }) => (
    <TextField
      key={formikRef}
      helperText={getIn(formik.touched, formikRef) ? getIn(formik.errors, formikRef) : ''}
      error={getIn(formik.touched, formikRef) && Boolean(getIn(formik.errors, formikRef))}
      value={getIn(formik.values, formikRef)}
      {...input}
      {...defaultProps.textField}
    />
  ))
}

Я также создал рабочая песочница ЗДЕСЬ

LE: Проверка типа была проблемой, но решение могло быть найдено с небольшим поиском ... Это обсуждалось здесь

Я внес исправления и добавил getIn вспомогательную функцию из Formik, чтобы пройти проверку типов.

...