Рефакторинг практически одинаковых компонентов, формик реагирует - PullRequest
0 голосов
/ 01 января 2019

У меня есть два идентичных компонента и только несколько различий (один).Есть два много повторяющихся кода и шаблон, но я не уверен, как реорганизовать это так, чтобы мне нужно было только указать конфигурацию.

LoginPage.js

import React from 'react';
import { Link } from 'react-router-dom';
import { Helmet } from 'react-helmet';
import { Formik, FastField, Form, ErrorMessage } from 'formik';

import PropTypes from 'prop-types';
import { FormDebug } from 'utils/FormDebug';
import { LoginValidationSchema } from 'validations/AuthValidationSchema';

function LoginPage({ username, onChangeUsername, onSubmitForm }) {
  return (
    <div>
      <Helmet>
        <title>Login</title>
      </Helmet>
      <Formik
        initialValues={{ username, password: '' }}
        validationSchema={LoginValidationSchema}
        onSubmit={onSubmitForm}
        render={({ isSubmitting, isValid, handleChange }) => (
          <Form>
            <FastField
              type="text"
              name="username"
              render={({ field }) => (
                <input
                  {...field}
                  onChange={e => {
                    handleChange(e);
                    onChangeUsername(e);
                  }}
                />
              )}
            />
            <ErrorMessage name="username" component="div" aria-live="polite" />
            <FastField type="password" name="password" />
            <ErrorMessage name="password" component="div" aria-live="polite" />
            <button type="submit" disabled={isSubmitting || !isValid}>
              Login
            </button>
            <FormDebug />
          </Form>
        )}
      />
      <Link to="/auth/forgot_password">Forgot Password</Link>
    </div>
  );
}

LoginPage.propTypes = {
  username: PropTypes.string,
  onSubmitForm: PropTypes.func.isRequired,
  onChangeUsername: PropTypes.func.isRequired,
};

export default LoginPage;

ForgotPasswordPage.js

import React from 'react';
import { Helmet } from 'react-helmet';
import { Formik, FastField, Form, ErrorMessage } from 'formik';

import PropTypes from 'prop-types';
import { FormDebug } from 'utils/FormDebug';
import { ForgotPasswordValidationSchema } from 'validations/AuthValidationSchema';

function ForgotPasswordPage({ username, onChangeUsername, onSubmitForm }) {
  return (
    <div>
      <Helmet>
        <title>Forgot Password</title>
      </Helmet>
      <Formik
        initialValues={{ username }}
        validationSchema={ForgotPasswordValidationSchema}
        onSubmit={onSubmitForm}
        render={({ isSubmitting, isValid, handleChange }) => (
          <Form>
            <FastField
              type="text"
              name="username"
              render={({ field }) => (
                <input
                  {...field}
                  onChange={e => {
                    handleChange(e);
                    onChangeUsername(e);
                  }}
                />
              )}
            />
            <ErrorMessage name="username" component="div" aria-live="polite" />
            <FormDebug />
            <button type="submit" disabled={isSubmitting || !isValid}>
              Reset Password
            </button>
          </Form>
        )}
      />
    </div>
  );
}

ForgotPasswordPage.propTypes = {
  username: PropTypes.string,
  onSubmitForm: PropTypes.func.isRequired,
  onChangeUsername: PropTypes.func.isRequired,
};

export default ForgotPasswordPage;

Как вам это сделать, если бы вы были мной.

Я думаю, что HOC., Но я не уверен, как назвать передать "детей", что отличается

Ответы [ 3 ]

0 голосов
/ 06 января 2019

Извините, если вы не ищете общий ответ, но я не думаю, что вы улучшите ремонтопригодность, обобщив то, что может быть просто коррелированными компонентами.Я ожидаю, что эти компоненты будут дрейфовать друг от друга по мере того, как вы будете совершенствовать свое приложение, например, добавив социальный логин, опцию «запомнить меня», капчу, опцию для получения имени пользователя и пароля по электронной почте, различную обработку неизвестного имени пользователя при получении пароля и подписив, и т. д. Кроме того, это часть вашего компонента, вы действительно не хотите ошибаться, так что KISS и все.Наконец, рассмотрим, существует ли на самом деле третий вариант использования для такого полуобобщенного компонента формы «логин или пароль извлечения».

Тем не менее, небольшое улучшение может быть достигнуто, например, путем создания повторно используемого компонента UsernameField, использованияиз которых будет простым и последовательным в обоих случаях.Также рассмотрите возможность использования withValidation HOC для добавления сообщения об ошибке в поле.Если вы действительно хотите растянуть его, вы можете иметь withSubmit HOC для Formik, передать все реквизиты в Formik, отобразить дочерние элементы (которые вы бы передали handleChange prop) и кнопку отправки.Я предполагаю, что форма сама использует контекст для передачи состояния в ErrorMessage и FastField.

0 голосов
/ 09 января 2019

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

Например, вы можете обернуть компонент formik в свою собственную обертку, а затем обернуть, например, компонент ввода, который работает с вашей новой формой.,Хорошим упражнением в сокращении котельной плиты может быть стремление к какому-либо варианту этого конечного результата

<CoolForm 
  initialValues={{ username, password: '' }}
  validationSchema={LoginValidationSchema}
>
  <CoolFormInputWithError someProps={{howeverYou: 'want to design this'}}>
  <CoolFormInputWithError someProps={{howeverYou: 'want to design this'}}>
  <CoolFormSubmit>
    Login
  </CoolFormSubmit>
  <FormDebug />
</CoolForm>

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

0 голосов
/ 04 января 2019

Я могу упустить некоторую сложность, не указанную здесь, но это выглядит так же просто, как создание универсального функционального компонента, который принимает еще пару переданных свойств.Я сделал diff, и вам нужно будет только добавить «title», «buttonText» и, если хотите, «type» к вашим реквизитам, наверняка.Вы также можете отправить объект initialValues ​​в качестве реквизита вместо того, чтобы выводить его из 'type'.

Я имею в виду, вы пробовали следующее?

import React from 'react';
import { Link } from 'react-router-dom';
import { Helmet } from 'react-helmet';
import { Formik, FastField, Form, ErrorMessage } from 'formik';

import PropTypes from 'prop-types';
import { FormDebug } from 'utils/FormDebug';
import * as schema from 'validations/AuthValidationSchema';

function AuthPage({ buttonText, initialValues, title, type, username,
                    onChangeUsername, onSubmitForm }) {
  const authSchema = type === 'login' 
        ? schema.LoginValidationSchema 
        : schema.ForgotPasswordValidationSchema;

  return (
    <div>
      <Helmet>
        <title>{title}</title>
      </Helmet>
      <Formik
        initialValues={initialValues}
        validationSchema={authSchema}
        onSubmit={onSubmitForm}
        render={({ isSubmitting, isValid, handleChange }) => (
          <Form>
            <FastField
              type="text"
              name="username"
              render={({ field }) => (
                <input
                  {...field}
                  onChange={e => {
                    handleChange(e);
                    onChangeUsername(e);
                  }}
                />
              )}
            />
            <ErrorMessage name="username" component="div" aria-live="polite" />
            {type === 'forgot' &&
              <FastField type="password" name="password" />
              <ErrorMessage name="password" component="div" aria-live="polite" />
            }
            <button type="submit" disabled={isSubmitting || !isValid}>
              {buttonText}
            </button>
            <FormDebug />
          </Form>
        )}
      />
      <Link to="/auth/forgot_password">Forgot Password</Link>
    </div>
  );
}

AuthPage.propTypes = {
  buttonText: PropTypes.string,
  initialValues: PropTypes.object,
  title: PropTypes.string,
  type: PropTypes.oneOf(['login', 'forgot'])
  username: PropTypes.string,
  onSubmitForm: PropTypes.func.isRequired,
  onChangeUsername: PropTypes.func.isRequired,
};

export default AuthPage;

(Единственное, что я не могу вспомнить, так это: нужно ли оборачивать условное отображение поля пароля и его ErrorMessage в divили не делать их одним элементом)

Если вы не хотите передавать начальные значения:

  const initialVals = type === 'login'
        ? { username, password: ''}
        : { username }
  ...
  initialValues={initialVals}

и удалить его из propTypes

Только другое, что яЯ не уверен, почему FormDebug размещается по-разному в двух версиях.Я оставил это после кнопки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...