• English
  • ProComponents 2.0 to 3.0 Migration Guide

    Overview

    ProComponents 3.0 is a major version upgrade that includes some breaking changes. This guide will help you smoothly migrate from version 2.0 to 3.0.

    Preparation Before Upgrade

    Version Requirements

    Dependency2.x Baseline3.0 Minimum Requirement
    antd>= 4.20.0>= 6.0.0
    React>= 16.9.0>= 18.0.0

    v3 Uses a Single Package

    ProComponents v3 only publishes @ant-design/pro-components. There are no v3 releases of the standalone @ant-design/pro-form, @ant-design/pro-table, @ant-design/pro-layout, or other @ant-design/pro-* packages. The latest standalone packages on npm belong to the v2 dependency tree and their peer dependencies only cover antd 4/5, so they must not be mixed with antd 6.

    Import components from the single package:

    import { ProForm, ProLayout, ProTable } from '@ant-design/pro-components';

    Remove direct dependencies on every standalone @ant-design/pro-* package and keep only @ant-design/pro-components. If pnpm why @ant-design/pro-form still finds a standalone package, inspect upstream dependencies such as Umi plugins. For Umi projects, upgrade both Umi and @umijs/plugins to 4.6.2 or later before moving to ProComponents v3.

    Codebase Preparation Suggestions

    • Create a migration branch in your version control system and lock the 2.x rollback baseline.
    • Run existing tests and self-test key pages before upgrading, recording passing results and screenshots for regression comparison.
    • Check if there are any polyfills/shim codes for antd@4 or React 16 in the project, and mark them for deletion in advance.
    • If the project uses a lockfile, please update and commit it at once during migration to avoid drift caused by repeated installations.

    Dependency Installation Example

    Taking pnpm as an example (please replace with corresponding commands if using npm or yarn):

    pnpm add antd@^6 @ant-design/pro-components@beta
    pnpm install

    Verify that the project no longer contains a v2 standalone dependency tree:

    pnpm why @ant-design/pro-components
    pnpm why @ant-design/pro-form
    pnpm why @ant-design/pro-table
    pnpm why @ant-design/pro-layout

    Do not use overrides or resolutions to replace a dependency's required v2 package with v3. Their package layouts and runtime requirements differ; upgrade the dependency that brings in v2 instead.

    Risk Warning

    • 3.0 completely removes the compatibility logic for antd@4. Mixing 2.x and 3.x components in the same package will trigger unexpected style and runtime errors.
    • React 18 concurrent features may expose issues with old side effect patterns. Please pay special attention to undeclared dependencies in useEffect or synchronous side effects.
    • If your build tool relies on old configurations of less-loader or babel-plugin-import, please check if they support the Token system of antd 5 after the upgrade.

    Installation and Build Troubleshooting

    antd 6 peer warnings or two ProComponents trees in node_modules

    The v3 package declares antd: ^6.0.0. If an install check still reports antd 4/5 peer warnings for @ant-design/pro-form, @ant-design/pro-layout, or other standalone packages, the dependency tree still contains v2 packages. Locate the source first:

    pnpm why @ant-design/pro-components
    pnpm why @ant-design/pro-form
    pnpm why @ant-design/pro-layout
    pnpm list antd --depth 10

    Umi projects usually need Umi and @umijs/plugins 4.6.2 or later before the old lockfile tree is removed and installed again. Do not use overrides to replace the v2 package required by Umi with v3; Umi would load incompatible exports at runtime.

    Can't resolve 'rc-util'

    This error comes from the v2 standalone packages. v3 directly declares @rc-component/util, so a normal v3 install does not require an application to add rc-util. Use pnpm why rc-util to find the old package and upgrade the whole group. For an application that must stay on v2, let the package manager install the rc-util@^5 declared by each package and check that the build does not exclude it; adding it to the application is only a temporary v2 workaround.

    A build fails after upgrading only ProTable

    The v2 standalone packages use coordinated internal versions and cannot be upgraded one at a time across generations. For example, @ant-design/pro-table@2.80.8 installs the v1 Form, Field, Card, and Utils packages. Mixing those with newer Layout/Form packages expands the dependency tree and creates compile conflicts. Upgrade @ant-design/pro-components as a unit. If the application must stay on v2, restore the previously verified group from the lockfile instead of raising a single package.

    Umi 3 fails with symbol.charCodeAt is not a function

    This error occurs when the Umi 3 build pipeline processes path-to-regexp@8, which is brought in by v2 @ant-design/pro-layout@7.20.1+. The long-term fix is Umi 4.6.2+ with ProComponents v3. If Umi 3 must be retained temporarily, restore a verified v2 lockfile; 7.20.0 is the last Layout release that uses path-to-regexp@2.4.0. Do not override only path-to-regexp, because its v2 and v8 APIs are incompatible.

    Next.js 14 throws while reading Group

    App Router files are Server Components by default. Put interactive form code behind a client boundary and prefer named components so that Next.js import optimization does not split a dot subcomponent incorrectly:

    'use client';
    
    import {
      LoginForm,
      ProFormGroup,
      ProFormText,
    } from '@ant-design/pro-components';
    
    export default function LoginPage() {
      return (
        <LoginForm>
          <ProFormGroup>
            <ProFormText name="username" />
          </ProFormGroup>
        </LoginForm>
      );
    }

    For App Router, also configure @ant-design/nextjs-registry in the root layout as described in the antd Next.js guide. v3 exports ProFormGroup directly, so module initialization does not have to read ProForm.Group.

    antd 4 is blocked by a ColorPicker import

    This is a historical publishing problem in @ant-design/pro-components@2.4.4: its broad ^ ranges can resolve @ant-design/pro-field@2.14.6. A verifiable v2 baseline is @ant-design/pro-components@2.6.42, which pins @ant-design/pro-field@2.14.1. Upgrade the package as a unit and commit the lockfile. Do not install pro-field@2.14.6 separately in an antd 4 project.

    Removed Deprecated APIs

    Change Cheat Sheet

    ComponentOld UsageNew UsageSuggestion
    ProTablecolumnsStateMapcolumnsState.value + columnsState.onChangeMigrate the original state object to columnsState.value and use onChange for events; if persistence is needed, add persistenceKey.
    ProTablehideInSearchsearch: falseUse search configuration to control the display of the search area, supporting object expansion.
    ProTablefixHeaderscroll: { y: number }Use antd Table native scroll property and set height as needed.
    ProTabletiptooltipMigrate column hints to tooltip, reusable with antd LabelTooltipType.
    ProCardProCard.TabPanetabs.itemsUse antd Tabs's items property to describe tabs, and pass other tabs configurations.
    ProCardStatisticsCardPropsStatisticCardPropsUpdate type references to avoid compilation errors.
    ProLayoutrightContentRenderactionsRender + avatarPropsSplit the original right side content into action area and avatar configuration for independent maintenance.
    Layout TokenmarginInlinePageContainerContent etc.paddingInlinePageContainerContent etc.Replace Token names comprehensively to maintain theme granularity consistency.
    ProFormFieldplainvariantRemove plain, use variant to control field display variant (e.g. borderless, outlined).
    ProListmetascolumns + listSlotConvert metas object key-value pairs to columns array elements, key becomes listSlot. See ProList Migration.

    Table Component

    1. columnsStateMap → columnsState

    Reason for change: Unify API naming for better consistency

    // ❌ Old version
    <ProTable
      columnsStateMap={{
        name: { show: false },
        age: { fixed: 'left' }
      }}
      onColumnsStateChange={(map) => console.log(map)}
    />
    
    // ✅ New version
    <ProTable
      columnsState={{
        value: {
          name: { show: false },
          age: { fixed: 'left' }
        },
        onChange: (map) => console.log(map)
      }}
    />

    columnsState is now fully aligned with the controlled mode of antd Table. It is recommended to migrate as follows:

    • Copy the original columnsStateMap fully to columnsState.value.
    • If you need to listen for changes, use columnsState.onChange; onColumnsStateChange has been removed, please migrate to columnsState.onChange.
    • If the project relies on column configuration persistence, please explicitly add persistenceKey and persistenceType.
    <ProTable
      columnsState={{
        value: columnsStateFromServer,
        defaultValue: defaultColumnsState,
        persistenceKey: 'user-table-columns',
        persistenceType: 'localStorage',
        onChange: setColumnsState,
      }}
    />

    defaultValue will take effect on the first render and after clearing persistence. Make sure to keep it consistent with the format returned by the server to avoid overwriting user configuration.

    2. hideInSearch → search: false

    Reason for change: Unify search-related properties

    // ❌ Old version
    const columns = [
      {
        title: 'Name',
        dataIndex: 'name',
        hideInSearch: true,
      },
    ];
    
    // ✅ New version
    const columns = [
      {
        title: 'Name',
        dataIndex: 'name',
        search: false,
      },
    ];

    search supports boolean values or objects:

    • Set to false: Completely hide the item in the search form.
    • Set to { transform }: Keep the search item but perform secondary processing on the submission process.
    const columns = [
      {
        title: 'Create Time',
        dataIndex: 'createdAt',
        valueType: 'dateRange',
        search: {
          transform: (value) => ({
            startTime: value?.[0],
            endTime: value?.[1],
          }),
        },
      },
    ];

    When migrating, please check if you relied on the default value of hideInSearch (previously false). If you expect to keep the search item, be sure to remove the old field instead of simply replacing it.

    3. fixHeader → scroll: { y: 400 }

    Reason for change: Use more standard antd Table scroll properties

    // ❌ Old version
    <ProTable
      fixHeader={true}
      // other props...
    />
    
    // ✅ New version
    <ProTable
      scroll={{ y: 400 }}
      // other props...
    />

    The y value of scroll is recommended to be decoupled from the page layout and can be dynamically calculated based on the container height:

    const height = document.body.clientHeight - 320;
    
    <ProTable
      scroll={{ y: height }}
      sticky
      // other props...
    />;

    If the project uses sticky combined with fixHeader, now simply keep sticky, and other scrolling behaviors are handled by antd native Table to avoid double positioning.

    4. tip → tooltip

    Reason for change: Unify tooltip property naming

    // ❌ Old version
    const columns = [
      {
        title: 'Name',
        dataIndex: 'name',
        tip: 'Please enter your name',
      },
    ];
    
    // ✅ New version
    const columns = [
      {
        title: 'Name',
        dataIndex: 'name',
        tooltip: 'Please enter your name',
      },
    ];

    tooltip is consistent with the tooltip type of antd FormItem, which can be either a string or a LabelTooltipType object, thus supporting richer descriptions and icon customization.

    const columns = [
      {
        title: 'Email',
        dataIndex: 'email',
        tooltip: {
          title: 'Company email, used for receiving notifications',
          icon: <InfoCircleOutlined />,
        },
      },
    ];

    The InfoCircleOutlined in the example needs to be imported from @ant-design/icons.

    When migrating, please confirm that there is no duplicate rendering of tooltip information with custom column rendering logic to avoid the same icon appearing multiple times.

    Card Component

    1. TabPane Component Removal

    Reason for change: Simplify API by using standard antd Tabs configuration

    // ❌ Old version
    <ProCard>
      <ProCard.TabPane tab="Tab 1" key="1">
        Content 1
      </ProCard.TabPane>
      <ProCard.TabPane tab="Tab 2" key="2">
        Content 2
      </ProCard.TabPane>
    </ProCard>
    
    // ✅ New version
    <ProCard
      tabs={{
        items: [
          {
            key: '1',
            label: 'Tab 1',
            children: 'Content 1'
          },
          {
            key: '2',
            label: 'Tab 2',
            children: 'Content 2'
          }
        ]
      }}
    />

    tabs directly reuses antd TabsProps. Precautions during migration:

    • tab, key, children and other fields of the original ProCard.TabPane map one-to-one to items.
    • If the old code passed cardProps through TabPane, now configure it uniformly in tabs.cardProps, or place children in each item of items to combine them yourself.
    • Control properties like tabs.onChange and tabs.activeKey remain unchanged and can be migrated directly.
    <ProCard
      tabs={{
        activeKey,
        onChange: setActiveKey,
        cardProps: {
          size: 'small',
          ghost: true,
        },
        items: tabItems,
      }}
    />

    If you customized the ProCard.TabPane component wrapper externally, you need to adjust the export method synchronously to avoid referencing static properties that have been deleted.

    2. StatisticsCardProps Type Removal

    Reason for change: Simplify type definitions

    // ❌ Old version
    import { StatisticsCardProps } from '@ant-design/pro-components';
    
    // ✅ New version
    import { StatisticCardProps } from '@ant-design/pro-components';

    This change only affects TypeScript types, and the compiler will prompt that StatisticsCardProps does not exist. Please replace it in the project's type declarations and custom wrapper components, especially for usages like React.FC<StatisticsCardProps>.

    Layout Component

    1. rightContentRender → actionsRender + avatarProps

    Reason for change: Separate concerns for more flexible configuration

    // ❌ Old version
    <ProLayout
      rightContentRender={() => (
        <div>
          <Avatar src="user.jpg" />
          <span>Username</span>
        </div>
      )}
    />
    
    // ✅ New version
    <ProLayout
      avatarProps={{
        src: 'user.jpg',
        title: 'Username'
      }}
      actionsRender={() => [
        <Button key="action1">Action 1</Button>,
        <Button key="action2">Action 2</Button>
      ]}
    />

    Recommended migration steps:

    1. Split the node returned by the original rightContentRender into "Avatar" and "Actions" contents.
    2. Put src, title, render, etc., related to the avatar into avatarProps; its type is compatible with antd AvatarProps, and provides additional title and render.
    3. Other buttons, search boxes, etc., are returned as an array from actionsRender, and ProLayout will handle spacing and alignment uniformly.
    <ProLayout
      avatarProps={{
        src: user.avatar,
        title: user.name,
        render: (props, dom) => (
          <Dropdown menu={{ items: userMenu }}>
            <a>{dom}</a>
          </Dropdown>
        ),
      }}
      actionsRender={({ isMobile }) => [
        !isMobile && <Switch key="theme" checked={dark} onChange={toggleTheme} />,
        <Button key="feedback" type="text" icon={<QuestionCircleOutlined />} />,
      ]}
    />

    The QuestionCircleOutlined in the example needs to be imported from @ant-design/icons.

    If the layout container (e.g., wrapped in a specific className) relying on rightContentRender was used before, after migration, you can wrap <Space> or custom components outside actionsRender to maintain consistent style.

    2. Layout Token Property Renaming

    Reason for change: Unify naming conventions

    // ❌ Old version
    const token = {
      layout: {
        pageContainer: {
          marginInlinePageContainerContent: 40,
          marginBlockPageContainerContent: 32,
        },
      },
    };
    
    // ✅ New version
    const token = {
      layout: {
        pageContainer: {
          paddingInlinePageContainerContent: 40,
          paddingBlockPageContainerContent: 32,
        },
      },
    };

    In addition to the fields in the example, other Tokens named with margin*PageContainerContent have also been switched to the corresponding padding*PageContainerContent. Please replace them all at once. After replacement, it is recommended to perform a theme build or visual acceptance to confirm that no old fields are missed.

    Field Component

    plain Parameter Removal

    Reason for change: Unify API by using variant to control display style

    // ❌ Old version
    <ProFormText
      name="name"
      plain={true}
    />
    
    <ProFormTimePicker
      name="time"
      plain
    />
    
    // ✅ New version
    <ProFormText
      name="name"
      fieldProps={{ variant: 'borderless' }}
    />
    
    <ProFormTimePicker
      name="time"
      fieldProps={{ variant: 'borderless' }}
    />

    The plain parameter has been completely removed and is no longer provided. For borderless/simplified display, use fieldProps.variant: 'borderless'; for default outlined style use variant: 'outlined'.

    When migrating, please search globally for plain, remove all plain or plain={true} props, and replace with variant configuration as needed.

    List Component

    metas → columns + listSlot

    Reason for change: Unify ProList and ProTable column configuration APIs so the same columns can be used for both table and list views

    ProList's metas API is deprecated. Use columns + listSlot instead. Migration rule: convert each key-value pair in the metas object to an element in the columns array, where the key becomes listSlot and the value's properties are spread into the column configuration.

    // ❌ Old version
    <ProList
      metas={{
        title: { dataIndex: 'name', title: 'Name' },
        avatar: { dataIndex: 'avatar', search: false },
        description: { dataIndex: 'desc', search: false },
        subTitle: {
          dataIndex: 'labels',
          render: (_, row) => <Tag>{row.label}</Tag>,
          search: false,
        },
        actions: {
          render: (_, row) => [<a key="edit">Edit</a>],
          search: false,
        },
        status: {
          title: 'Status',
          valueType: 'select',
          valueEnum: { open: { text: 'Open' }, closed: { text: 'Closed' } },
        },
      }}
    />
    
    // ✅ New version
    <ProList
      columns={[
        { title: 'Name', dataIndex: 'name', listSlot: 'title' },
        { dataIndex: 'avatar', listSlot: 'avatar', search: false },
        { dataIndex: 'desc', listSlot: 'description', search: false },
        {
          dataIndex: 'labels',
          listSlot: 'subTitle',
          render: (_, row) => <Tag>{row.label}</Tag>,
          search: false,
        },
        {
          listSlot: 'actions',
          render: (_, row) => [<a key="edit">Edit</a>],
          search: false,
        },
        {
          title: 'Status',
          dataIndex: 'status',
          valueType: 'select',
          valueEnum: { open: { text: 'Open' }, closed: { text: 'Closed' } },
        },
      ]}
    />

    Migration reference:

    metas syntaxcolumns syntax
    title: { dataIndex: 'name' }{ dataIndex: 'name', listSlot: 'title' }
    avatar: { dataIndex: 'img' }{ dataIndex: 'img', listSlot: 'avatar' }
    description: { dataIndex: 'desc' }{ dataIndex: 'desc', listSlot: 'description' }
    subTitle: { render: ... }{ listSlot: 'subTitle', render: ... }
    content: {}{ dataIndex: 'content', listSlot: 'content' }
    extra: { render: ... }{ listSlot: 'aside', render: ... }
    type: {}{ dataIndex: 'type', listSlot: 'type' }

    Tip: metas keys without a corresponding listSlot (e.g. status) use the key name as dataIndex. When migrating, you need to explicitly add dataIndex. After migration, the same columns can be directly passed to ProTable, enabling one-click switching between list and table views. See ProList documentation.

    1. Remove antd@4 Compatibility Code

    Reason for change: Focus on antd@6 support and simplify codebase

    • Removed compareVersions utility function
    • Removed coverToNewToken compatibility function
    • Removed all antd@4 related compatibility checks

    If you explicitly imported the above utility functions in your business code (common in theme customization or style fallback scenarios), you need to delete them synchronously and use the Token scheme officially recommended by antd 5. If theme variables are lost after the upgrade, prioritize checking whether coverToNewToken is still being referenced.

    Upgrade Benefits

    1. Improved Type Support

    // Better TypeScript support
    interface DataType {
      id: number;
      name: string;
      age: number;
    }
    
    <ProTable<DataType>
      columns={[
        {
          title: 'Name',
          dataIndex: 'name',
          // Now has better type hints
        },
      ]}
    />;

    3.0 has made the following improvements to the type system:

    • Generic components like ProTable and ProForm have stricter derivation for columns/fields, reducing any.
    • New columnsState and search APIs have complete type declarations, facilitating automatic editor prompts.
    • The single package publishes all component declarations, avoiding duplicate standalone package types in node_modules.

    If you encounter type errors after migration, please prioritize checking whether custom encapsulations explicitly declare old types of 2.x (such as ProColumns<any>); if necessary, just add generic parameters.

    2. Simplified API Design

    // More concise configuration
    <ProForm
      layout="vertical"
      onFinish={async (values) => {
        console.log(values);
        return true;
      }}
    />
    • ProForm no longer preloads all field components by default, making Tree Shaking friendlier.
    • The action area of ProLayout is easier to render on demand after splitting, avoiding writing a lot of conditional branches.
    • After ProCard is aligned with antd Tabs, all configuration items and animations of antd can be reused directly.

    Understanding these benefits helps evaluate the value of the upgrade and communicate the benefits to the team.

    Migration Steps

    1. Update Dependencies

    Prioritize using the project's current package manager to maintain consistency. The following example uses pnpm:

    # Upgrade core dependencies
    pnpm add antd@^6 @ant-design/pro-components@beta
    
    # Synchronize installation lock version
    pnpm install

    If the team still uses npm/yarn, please replace pnpm up with the corresponding npm install or yarn add command, and confirm that package-lock.json/yarn.lock is updated at once.

    2. Check for Deprecated APIs

    Use the following commands to help troubleshoot (if rg is not installed, replace with grep or IDE global search):

    # Use ripgrep (recommended)
    pnpm exec rg "columnsStateMap" src
    pnpm exec rg "hideInSearch" src
    pnpm exec rg "fixHeader" src
    pnpm exec rg "tip[\"']" src
    pnpm exec rg "ProCard\.TabPane" src
    pnpm exec rg "rightContentRender" src
    pnpm exec rg "plain" src
    pnpm exec rg "metas" src

    In Windows PowerShell, you can use Select-String -Path "src/**/*.tsx" -Pattern "columnsStateMap" to achieve a similar effect.

    3. Gradual Migration

    1. First migrate Table components

      • Update columnsStateMap to columnsState
      • Update hideInSearch to search: false
      • Update fixHeader to scroll: { y: 400 }
      • Update tip to tooltip
      • Add columnsState.defaultValue, persistenceKey on demand
    2. Then migrate Card components

      • Change TabPane usage to tabs.items
      • Update type references to ensure StatisticsCardProps is no longer imported
    3. Finally migrate Layout components

      • Update rightContentRender to actionsRender + avatarProps
      • Update layout token property names
      • Check if custom header components rely on the old rightContentRender container
    4. Migrate List components

      • Convert the metas object to a columns array
      • Convert each meta key to a listSlot property
    5. Migrate Field / ProFormField components

      • Remove all plain or plain={true} props
      • Replace with fieldProps.variant: 'borderless' or variant: 'outlined' as needed

    Migrating from data-intensive components to layout components helps ensure data display is correct before dealing with visual differences.

    4. Test and Verify

    # Run unit tests (coverage recommended)
    pnpm run test
    
    # Build artifacts, verify packaging output
    pnpm run build
    
    # Start dev server for end-to-end verification
    pnpm run dev
    
    # (Optional) Static check
    pnpm run lint

    Focus on the following scenarios during verification:

    • Whether the table column configuration is correctly persisted, and whether the column setting panel can save user preferences.
    • Whether the display of the operation area in the upper right corner of the layout meets expectations on mobile and desktop.
    • Whether custom theme Tokens are still correctly read, and there are no Warning: [antd: theme] class warnings in the console.

    FAQ

    Q: What should I do if TypeScript errors occur after upgrade?

    A: Common reasons include still referencing StatisticsCardProps, columnsStateMap, or hardcoding old fields in custom types. Please adjust according to this document and confirm that types in tsconfig.json does not point to custom declarations of 2.x.

    Q: What if table column state is no longer persisted?

    A: Check if persistenceKey and persistenceType have been set in columnsState, and whether value is a new object reference. 3.0 will ignore cases where old objects are directly reused. If necessary, use structuredClone or manual JSON.parse(JSON.stringify(...)).

    Q: Tabs do not render after upgrade?

    A: The new tabs.items must provide key and label, and ensure that the items array is not filtered to undefined dynamically during the rendering process. If you rely on lazy loading, please control the rendering timing yourself in children.

    Q: The top right action area disappeared?

    A: actionsRender needs to return ReactNode[] or a single ReactNode. Please confirm that the return value of the function is not undefined. If you need to control based on permissions, you can return null or an empty array, but don't forget the final return value.

    Q: What should I do if component styles are abnormal after upgrade?

    A: First confirm that antd has been upgraded to 6.0.0+, and then troubleshoot whether there are still custom styles referencing removed class names (such as .ant-pro-card-tabpane). After Token renaming, variables in LESS/SCSS also need to be updated synchronously.

    Q: What should I do if functionality doesn't work after upgrade?

    A: Open the browser console and terminal logs, which usually prompt for unmigrated APIs. Please troubleshoot one by one in combination with the commands in the "Check Removed APIs" chapter.

    Q: Can I upgrade incrementally?

    A: Not recommended. 3.0 removes the antd@4 compatibility layer and unifies the types of multiple upstream and downstream packages. Forcibly mixing 2.x and 3.x components is extremely likely to cause runtime or style issues.

    Rollback Plan

    If you encounter problems during the upgrade process, you can rollback to version 2.0:

    # Rollback to version 2.0
    pnpm up @ant-design/pro-components@^2.8.10
    pnpm up antd@^4.24.0

    Similarly, please ensure that the lock file and dependencies are restored to the commit before the migration when rolling back.

    Summary

    The ProComponents 3.0 upgrade is mainly for:

    1. Simplify codebase - Remove deprecated compatibility code
    2. Improve performance - Reduce unnecessary checks and warnings
    3. Unify API - Provide more consistent development experience
    4. Modernize - Focus on antd@6 and modern React features

    Although the upgrade process may require some work, these improvements will provide a better foundation for future development. If you encounter any issues during the migration process, please refer to the official documentation or submit an issue.