【问题标题】:How to handle React components that have intensive logic?如何处理具有密集逻辑的 React 组件?
【发布时间】:2020-02-19 12:07:08
【问题描述】:

模板问题

问题

大家好!

最近我注意到在我工作的应用程序中创建了一些逻辑密集型的反应组件,这些组件通常有几十行我称之为“设置逻辑”(需要在渲染之前设置的变量)我的组件)。其中一些内容可以是:

  • 向翻译服务发送请求以检索该组件所需的翻译字符串
  • 从状态创建派生数据,例如:
    • 是否显示来自 API 的给定功能标志的组件
    • 给定 API 收到的初始值和最终值的进度条百分比
  • 获取当前用户
  • 获取默认品牌颜色和字体大小
  • 用户单击按钮时将执行的突变/查询
  • 将所有这些信息映射到样式组件和子组件

这就引出了“我们在这些组件上做得太多了吗?”的问题

毫无疑问是的,但我们究竟如何将其分开?我们在哪里画线?

啊,请注意,这是我们目前的设置:

堆栈信息:

前端:反应

API:GraphQL

可能的解决方案

将设置逻辑(getter、mapper 和查询)与表示逻辑(JSX)分开。

问题 1。 是否应该有一个组件专门负责为其逻辑服务于表示组件?

问题 2。 这应该完全是一个组件,还是应该由 graphQL API 提供这个逻辑? 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;

【问题讨论】:

  • 您可以创建可重用的功能组件来分离出重复的部分。
  • @Niraj 这是个好主意!只是想看看我是否理解,当您说function components 时,您的意思是functional components,还是还有其他我不知道的概念?干杯!
  • 是的,相同的功能组件只负责获取道具并在重新渲染时返回更新的组件。

标签: reactjs architecture refactoring


【解决方案1】:

你需要创建函数组件来分离出重复的部分,这样你就可以在你的主要组件中用作一个元素,也可以重复使用它。

【讨论】:

    猜你喜欢
    • 2020-05-04
    • 2022-01-24
    • 2012-11-15
    • 1970-01-01
    • 2019-03-03
    • 1970-01-01
    • 2010-10-05
    • 2020-10-03
    • 1970-01-01
    相关资源
    最近更新 更多