Как обращаться с компонентами React, которые имеют интенсивную логику c? - PullRequest
1 голос
/ 19 февраля 2020

Шаблон Вопроса

Проблема

Привет, ребята!

Недавно я заметил несколько очень логичных c -интенсивных компонентов реакции, создаваемых в приложении I работать, и у этих компонентов обычно есть десятки строк, которые я называю «setup logi c» (переменные, которые необходимо установить перед тем, как я рендерил свой компонент). Вот некоторые из этих вещей:

  • Отправка запроса в службу перевода для получения необходимых переведенных строк для этого компонента
  • Создание производных данных из состояний, таких как:
    • показывать или нет компонент с данным флагом функции из API
    • Процент индикатора выполнения с учетом начального и конечного значения, полученного API
  • Получение currentUser
  • Получение фирменных цветов и размеров шрифта по умолчанию
  • Мутации / запросы, которые будут выполняться, когда пользователь нажимает кнопку
  • Отображение всей этой информации в стиль компоненты и дочерние компоненты

Возникает вопрос: «Мы слишком много делаем в этих компонентах?»

Несомненно, да, но как именно мы разбиваем это на части? Где мы рисуем линию?

Ах, и на голову, это наша установка в настоящее время:

Информация о стеке:

Внешний интерфейс: Реагировать

API: GraphQL

Возможное решение

Отделение лога установки c (получателей, преобразователей и запросов) от лога представления c (JSX).

Вопрос 1. Если существует компонент, который несет полную ответственность за обслуживание компонента презентации с его логами c?

Вопрос 2. Должен ли это вообще быть компонентом или эта логика c должна обслуживаться API-интерфейсом GraphQL? Насколько связан GraphQL с компонентом React?

Пример кода

Это пример, иллюстрирующий проблему:

// 30 lines of *import*
// ...

const MyForm = ({
  onSubmit,
  initialValues,
  children,
  loading,
  isCreating,
  cycleId,
  permissions,
  otherPermissions,
  showWeightBalance,
  balance,
}) => {
  const { t } = useTranslation();
  const currentUser = useCurrentUser();
  const cycle = useCycle({ id: cycleId });
  const canUpdateFields =
    isCreating || (permissions && permissions.update);
  const canUpdateContributors =
    isCreating ||
    (permissions && permissions.updateContributors);
  const canReassignResponsible =
    isCreating ||
    (permissions && permissions.reassignResponsible);
  const canUpdateWeight =
    isCreating ||
    (otherPermissions &&
      otherPermissions.updateWeight);
  const canShowContributorsInput =
    isCreating ||
    (permissions && permissions.showContributorsInputOnForm);

  return (
    <Form
      initialValues={{
        name: {},
        description: {},
        type: {
          kind: kind.NUMBER,
          direction: direction.ASC,
        },
        baseValue: null,
        target: null,
        unit: null,
        weight: 1,
        progressCalculus: false,
        responsible: null,
        contributors: [],
        tasks: [],
        scale: null,
        ...initialValues,
      }}
      onSubmit={onSubmit}
      key={JSON.stringify(initialValues)} // This is made to reset the form when new initial values get loaded, should be enableReinitialize but richtexteditor wouldn't reset
    >
      {formProps => (
        <Fragment>
          <FormFieldTextTranslations
            name="name"
            label={t('yml_path')}
            subtitle={t('yml_path')}
            placeholder={t('yml_path')}
            locales={locale.availableLocales()}
            validate={[
              requiredTranslation(t('yml_path')),
            ]}
            disabled={loading || !canUpdateFields}
          />
          <FormFieldRichTextTranslations
            name="description"
            label={t('yml_path')}
            subtitle={t('yml_path')}
            placeholder={t(
              'yml_path',
            )}
            locales={locale.availableLocales()}
            optional
            hideToolbar
            minimumLines={4}
          />
          <FormFieldGroup
            name="type"
            label={t('yml_path')}
            validate={[required('yml_path')]}
          >
            <Layout display="flex" flexWrap="wrap">
              <FormFieldRadio
                mr="px32"
                mb={['px8', 'none']}
                disabled={loading || !isCreating}
                name="type"
                value={{
                  kind: kind.NUMBER,
                  direction: direction.ASC,
                }}
                label={(checked, disabled, error) => (
                  <RadioCard
                    iconProps={{
                      iconName: 'chart-line',
                      solid: true,
                      fontSize: '20px',
                    }}
                    text={t(
                      'yml_path',
                    )}
                    checked={checked}
                    disabled={disabled}
                    error={error}
                  />
                )}
              />
              <FormFieldRadio
                mr="px32"
                mb={['px8', 'none']}
                disabled={loading || !isCreating}
                name="type"
                value={{
                  kind: kind.NUMBER,
                  direction: direction.DESC,
                }}
                label={(checked, disabled, error) => (
                  <RadioCard
                    iconProps={{
                      iconName: 'chart-line-down',
                      solid: true,
                      fontSize: '20px',
                    }}
                    text={t(
                      'yml_path',
                    )}
                    checked={checked}
                    disabled={disabled}
                    error={error}
                  />
                )}
              />
              <FormFieldRadio
                mr="px32"
                mb={['px8', 'none']}
                disabled={loading || !isCreating}
                name="type"
                value={{
                  kind: kind.KEEP,
                  direction: formProps.values.type.direction,
                }}
                label={(checked, disabled, error) => (
                  <RadioCard
                    iconProps={{
                      iconName: 'chart-keep',
                      solid: true,
                      fontSize: '20px',
                    }}
                    text={t('yml_path')}
                    checked={checked}
                    disabled={disabled}
                    error={error}
                  />
                )}
              />
              <FormFieldRadio
                mb={['px8', 'none']}
                disabled={loading || !isCreating}
                name="type"
                value={{
                  kind: kind.BINARY,
                  direction: null,
                }}
                label={(checked, disabled, error) => (
                  <RadioCard
                    iconProps={{
                      iconName: 'check',
                      solid: true,
                      fontSize: '20px',
                    }}
                    text={t(
                      'yml_path',
                    )}
                    checked={checked}
                    disabled={disabled}
                    error={error}
                    tooltip={t(
                      'yml_path',
                    )}
                  />
                )}
              />
            </Layout>
          </FormFieldGroup>
          {formProps.values.type.kind === kind.NUMBER &&
            formProps.values.type.direction === direction.ASC && (
              <AscendingForm
                formProps={formProps}
                loading={loading}
                canUpdateFields={canUpdateFields}
                canUpdateWeight={canUpdateWeight}
                showWeightBalance={showWeightBalance}
                balance={balance}
                isCreating={isCreating}
              />
            )}
          {formProps.values.type.kind === kind.NUMBER &&
            formProps.values.type.direction === direction.DESC && (
              <DescendingForm
                formProps={formProps}
                loading={loading}
                canUpdateFields={canUpdateFields}
                canUpdateWeight={canUpdateWeight}
                showWeightBalance={showWeightBalance}
                balance={balance}
                isCreating={isCreating}
              />
            )}
          {formProps.values.type.kind === kind.KEEP && (
            <KeepForm
              loading={loading}
              canUpdateFields={canUpdateFields}
              canUpdateWeight={canUpdateWeight}
              showWeightBalance={showWeightBalance}
              balance={balance}
              isCreating={isCreating}
            />
          )}
          {formProps.values.type.kind === kind.BINARY && (
            <BinaryForm
              loading={loading}
              canUpdateWeight={canUpdateWeight}
              showWeightBalance={showWeightBalance}
              balance={balance}
              isCreating={isCreating}
            />
          )}
          {cycle &&
            (cycle.allowCustomScore ||
              cycle.allowScale) &&
            formProps.values.type.kind !== kind.BINARY && (
              <FormFieldGroup
                name="progressCalculus"
                label={t('yml_path')}
                validate={[
                  required(t('yml_path')),
                ]}
              >
                <FormFieldRadio
                  name="progressCalculus"
                  mb="px4"
                  label={t(
                    'yml_path',
                  )}
                  disabled={loading || !isCreating}
                  value={false}
                />
                {cycle.allowCustomScore && (
                  <FormFieldRadio
                    name="progressCalculus"
                    mb="px4"
                    label={t(
                      'yml_path',
                    )}
                    disabled={loading || !isCreating}
                    value={ProgressCalculusEnum.customScore}
                  />
                )}
                {cycle.allowScoreScale && (
                  <Fragment>
                    <FormFieldRadio
                      name="progressCalculus"
                      mb="px4"
                      label={t(
                        'yml_path',
                      )}
                      disabled={loading || !isCreating}
                      value={ProgressCalculusEnum.scale}
                    />
                    <ScaleRadioHelperNegativeMargin>
                      <FieldHelper
                        message={t(
                          'yml_path',
                        )}
                        iconName="info-circle"
                      />
                    </ScaleRadioHelperNegativeMargin>
                  </Fragment>
                )}
              </FormFieldGroup>
            )}
          {isCreating &&
            cycle &&
            cycle.allowScoreScale &&
            formProps.values.type.kind === kind.NUMBER &&
            formProps.values.progressCalculus ===
              ProgressCalculusEnum.scale && (
              <ScoreScaleForm
                name="scale.partitions"
                formProps={formProps}
              />
            )}
          <FormFieldSelectContract
            name="responsible"
            label={t('yml_path')}
            placeholder={t(
              'yml_path',
            )}
            filter={{ active: true }}
            validate={[
              required(
                t('yml_path'),
              ),
            ]}
            disabled={loading || !canReassignResponsible}
            allowClear
          />
          <AssignToMeWrapper>
            <Button
              kind="primary"
              size="adaptative"
              appearance="text"
              onMouseDown={() => {
                setTimeout(
                  () =>
                    formProps.setFieldValue('responsible', {
                      key: currentUser.id,
                      label: currentUser.name,
                    }),
                  20,
                );
              }}
            >
              {t('assign_to_me')}
            </Button>
          </AssignToMeWrapper>
          {canShowContributorsInput && (
            <FormFieldSelectContract
              name="contributors"
              mode="multiple"
              label={t('yml_path')}
              placeholder={t(
                'yml_path',
              )}
              filter={{ active: true }}
              optional
              disabled={loading || !canUpdateContributors}
            />
          )}
          {isCreating && (
            <FormFieldGroup
              name="tasks"
              label={t('yml_path')}
              optional
            >
              <TasksForm name="tasks" tasks={formProps.values.tasks} />
            </FormFieldGroup>
          )}
          <Layout mt="px40">{children(formProps)}</Layout>
        </Fragment>
      )}
    </Form>
  );
};

export default MyForm;

1 Ответ

0 голосов
/ 27 февраля 2020

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

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