使用多个选项卡和动态表单项优化表单渲染

问题描述 投票:0回答:1

我想有效地构造一个表单。我的目标是创建一个包含 5 个选项卡的页面,每个选项卡包含 10 个不同类型的唯一表单项,例如文本、数字和选择字段。我通过设置选项卡和选项卡内容区域来构建结构,并根据活动选项卡显示相应的选项卡内容。每个选项卡的 10 个表单项在常量中定义为具有类型的对象,允许表单组件根据类型呈现适当的表单项。布局显示正确,但渲染速度较慢。我怎样才能提高性能?下面是显示相关部分的部分代码示例。我非常感谢任何优化建议。

import React, { useState, useMemo } from 'react';
import {
  Tabs as UITabs,
  Tab as UITab,
  TabContent as UITabContent,
  FormInput,
  FormSelect,
  FormInputNumber,
} from 'your-ui-library';

const FORM_LIST = [
  {
    id: 0,
    key: 'school',
    title: 'School',
    fieldsList: SCHOOL_FIELDS,
  },
  {
    id: 1,
    key: 'college',
    title: 'College',
    fieldsList: COLLEGE_FIELDS,
  },
  {
    id: 2,
    key: 'university',
    title: 'University',
    fieldsList: UNIVERSITY_FIELDS,
  },
];

export const UNIVERSITY_FIELDS = [
  {
    type: 'select',
    name: '1',
    label: 'Region',
    description: 'test',
    options: [
      { label: 'Korea', value: 'korean' },
      { label: 'India', value: 'india' },
    ],
    validationRules: { required: 'Role selection is required' },
  },
  {
    type: 'inputNumber',
    name: '2',
    label: 'Minimum Letters',
    validationRules: { required: 'Number is required' },
  },
];

// Tabs Component
const Tabs = ({ tabs, activeTab, onTabChange }) => {
  return (
    <UITabs orientation="vertical" onChangeTab={(newTab) => onTabChange(newTab)} outline>
      {tabs.map((tab) => (
        <UITab key={tab.id} id={tab.id} label={tab.title}>
          {tab.title}
        </UITab>
      ))}
    </UITabs>
  );
};

// TabContent Component
const TabContent = ({ activeTab, tabs }) => {
  const content = useMemo(() => {
    return tabs
      .filter((tab) => tab.id === activeTab)
      .map((tab) => (
        <UITabContent key={tab.id} value={tab.id} activeTabNum={activeTab}>
          <FieldRenderContent fields={tab.fieldsList} />
        </UITabContent>
      ));
  }, [activeTab, tabs]);

  return <>{content}</>;
};

// FieldRenderer Component
const FieldRenderer = ({ field }) => {
  switch (field.type) {
    case 'input':
      return (
        <FormInput
          name={field.name}
          label={field.label}
          description={field.description}
          validationRules={field.validationRules}
        />
      );
    case 'select':
      return (
        <FormSelect
          name={field.name}
          label={field.label}
          options={field.options}
          description={field.description}
          isClearable={true}
          validationRules={field.validationRules}
        />
      );
    case 'inputNumber':
      return <FormInputNumber name={field.name} label={field.label} validationRules={field.validationRules} />;
    default:
      return null;
  }
};

// FieldRenderContent Component
const FieldRenderContent = ({ fields }) => {
  return (
    <>
      {fields.map((field) => (
        <FieldRenderer key={field.name} field={field} />
      ))}
    </>
  );
};

// Main Component
const FormPage = () => {
  const [activeTab, setActiveTab] = useState(0);

  return (
    <div style={{ display: 'flex' }}>
      {/* Tabs */}
      <div style={{ marginRight: '16px' }}>
        <Tabs tabs={FORM_LIST} activeTab={activeTab} onTabChange={setActiveTab} />
      </div>

      {/* Tab Content */}
      <div>
        <TabContent activeTab={activeTab} tabs={FORM_LIST} />
      </div>
    </div>
  );
};

export default FormPage;

javascript reactjs react-hook-form
1个回答
0
投票

可能的优化

  • 选项卡内容延迟加载:仅渲染活动选项卡的表单项 以避免所有选项卡不必要的重新渲染。目前,使用Memo 为所有选项卡创建内容数组,即使是那些不活动的选项卡。使用 条件渲染仅显示活动选项卡。
  • 记忆字段组件:避免重新渲染字段组件 不必要的。将 FieldRenderer 和 FieldRenderContent 记忆到 阻止它们重新渲染,除非字段数据本身发生变化
  • 避免内联函数:将handleTabChange函数移到外部 JSX 以避免在每次渲染时重新创建它。
  • useCallback 方法: 记住回调函数以防止在每次渲染时重新创建,如果作为 props 传递,这可能会导致子组件重新渲染。

完整示例:

import React, { useState, useMemo, memo, useCallback } from 'react';
import {
  Tabs as UITabs,
  Tab as UITab,
  TabContent as UITabContent,
  FormInput,
  FormSelect,
  FormInputNumber,
} from 'your-ui-library';

// Constant for Form Fields
const FORM_LIST = [
  {
    id: 0,
    key: 'school',
    title: 'School',
    fieldsList: SCHOOL_FIELDS,
  },
  {
    id: 1,
    key: 'college',
    title: 'College',
    fieldsList: COLLEGE_FIELDS,
  },
  {
    id: 2,
    key: 'university',
    title: 'University',
    fieldsList: UNIVERSITY_FIELDS,
  },
];

export const UNIVERSITY_FIELDS = [
  {
    type: 'select',
    name: '1',
    label: 'Region',
    description: 'test',
    options: [
      { label: 'Korea', value: 'korean' },
      { label: 'India', value: 'india' },
    ],
    validationRules: { required: 'Role selection is required' },
  },
  {
    type: 'inputNumber',
    name: '2',
    label: 'Minimum Letters',
    validationRules: { required: 'Number is required' },
  },
];

// Tabs Component (Memoized)
const Tabs = memo(({ tabs, activeTab, onTabChange }) => {
  return (
    <UITabs orientation="vertical" onChangeTab={onTabChange} outline>
      {tabs.map((tab) => (
        <UITab key={tab.id} id={tab.id} label={tab.title}>
          {tab.title}
        </UITab>
      ))}
    </UITabs>
  );
});

// TabContent Component with Lazy Loading
const TabContent = ({ activeTab, tabs }) => {
  const activeTabContent = useMemo(() => tabs.find((tab) => tab.id === activeTab), [activeTab, tabs]);

  return (
    <UITabContent key={activeTabContent.id} value={activeTabContent.id}>
      <FieldRenderContent fields={activeTabContent.fieldsList} />
    </UITabContent>
  );
};

// FieldRenderer Component (Memoized)
const FieldRenderer = memo(({ field }) => {
  switch (field.type) {
    case 'input':
      return (
        <FormInput
          name={field.name}
          label={field.label}
          description={field.description}
          validationRules={field.validationRules}
        />
      );
    case 'select':
      return (
        <FormSelect
          name={field.name}
          label={field.label}
          options={field.options}
          description={field.description}
          isClearable={true}
          validationRules={field.validationRules}
        />
      );
    case 'inputNumber':
      return (
        <FormInputNumber
          name={field.name}
          label={field.label}
          validationRules={field.validationRules}
        />
      );
    default:
      return null;
  }
});

// FieldRenderContent Component (Memoized)
const FieldRenderContent = memo(({ fields }) => {
  return (
    <>
      {fields.map((field) => (
        <FieldRenderer key={field.name} field={field} />
      ))}
    </>
  );
});

// Main FormPage Component
const FormPage = () => {
  const [activeTab, setActiveTab] = useState(0);

  const handleTabChange = useCallback((newTab) => {
    setActiveTab(newTab);
  }, []);

  return (
    <div style={{ display: 'flex' }}>
      {/* Tabs */}
      <div style={{ marginRight: '16px' }}>
        <Tabs tabs={FORM_LIST} activeTab={activeTab} onTabChange={handleTabChange} />
      </div>

      {/* Tab Content */}
      <div>
        <TabContent activeTab={activeTab} tabs={FORM_LIST} />
      </div>
    </div>
  );
};

export default FormPage;
© www.soinside.com 2019 - 2024. All rights reserved.