Skip to content

Instantly share code, notes, and snippets.

@architectureman
Created April 29, 2025 04:42
Show Gist options
  • Save architectureman/376c35765c4d80b3db926c9e49f629f3 to your computer and use it in GitHub Desktop.
Save architectureman/376c35765c4d80b3db926c9e49f629f3 to your computer and use it in GitHub Desktop.
Antd_mig

Báo cáo: Những hạn chế của Ant Design trong thiết kế tùy chỉnh cao

Giới thiệu

Ant Design (antd) là một trong những thư viện UI phổ biến nhất cho ứng dụng React, được phát triển bởi Alibaba và cộng đồng. Với hơn 80.000 sao trên GitHub, antd cung cấp một hệ thống thiết kế toàn diện với nhiều component được đóng gói sẵn, giúp tăng tốc quá trình phát triển giao diện người dùng.

Tuy nhiên, khi các dự án có nhu cầu thiết kế tùy chỉnh cao, đặc biệt là khi cần phá vỡ các quy tắc thiết kế chuẩn của Ant Design, nhà phát triển có thể gặp nhiều thách thức. Báo cáo này phân tích chi tiết các trường hợp mà Ant Design gặp khó khăn trong việc đáp ứng yêu cầu thiết kế tùy chỉnh, kèm theo ví dụ cụ thể và các giải pháp thay thế tiềm năng.

Mục lục

  1. Giới hạn về theme và styling
  2. Hạn chế về cấu trúc và hành vi component
  3. Thách thức về thiết kế responsive
  4. Vấn đề về hiệu suất
  5. Giới hạn về animation và transition
  6. Tùy chỉnh về accessibility
  7. Các component đặc biệt
  8. Kết luận và khuyến nghị

1. Giới hạn về theme và styling

1.1. Cấu trúc CSS phức tạp

Vấn đề: Ant Design sử dụng cấu trúc CSS phức tạp với nhiều lớp lồng nhau, làm cho việc ghi đè kiểu khó khăn mà không ảnh hưởng đến các thành phần khác.

Ví dụ: Tùy chỉnh Button trong Dropdown

// Khó tùy chỉnh vì cấu trúc lồng nhau phức tạp
<Dropdown
  overlay={
    <Menu>
      <Menu.Item>
        <Button type="primary">Action Button</Button> {/* Khó styling riêng cho button này */}
      </Menu.Item>
    </Menu>
  }
>
  <Button>Dropdown</Button>
</Dropdown>

Khi bạn muốn tùy chỉnh button trong Menu.Item, bạn phải đối mặt với các selector CSS phức tạp như:

.ant-dropdown .ant-menu .ant-menu-item .ant-btn {
  /* Các tùy chỉnh của bạn */
}

Selector này rất dễ gây xung đột với các thành phần khác trong ứng dụng.

1.2. Tùy chỉnh bên trong component

Vấn đề: Nhiều component của antd có cấu trúc DOM phức tạp và được đóng gói chặt chẽ, khó tùy chỉnh các phần tử bên trong mà không ảnh hưởng đến chức năng.

Ví dụ: Tùy chỉnh Table columns với content phức tạp

<Table
  columns={[
    {
      title: 'Name',
      dataIndex: 'name',
      render: (text, record) => (
        // Styling cho các phần tử trong ô rất khó
        <div className="custom-cell">
          <Avatar src={record.avatar} />
          <span>{text}</span>
          {record.status === 'online' && <Badge status="success" />}
        </div>
      )
    }
  ]}
  dataSource={data}
/>

Khi cần tùy chỉnh hover state hoặc làm highlight một phần cụ thể của nội dung cell, bạn phải đối mặt với các vấn đề phức tạp về CSS và DOM manipulation.

1.3. Màu sắc gradient phức tạp

Vấn đề: Hệ thống theme của antd chủ yếu dựa trên màu đơn, khó hỗ trợ các gradient phức tạp hoặc các hiệu ứng màu sắc tiên tiến.

Ví dụ: Button với gradient phức tạp

/* Gradient này rất khó tích hợp vào hệ thống theme của antd */
.custom-button {
  background: linear-gradient(90deg, #FF8A00 0%, #DA1B60 50%, #8A16C1 100%);
  color: white;
  border: none;
  transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
}
// Khi sử dụng với component Button
<Button className="custom-button">
  Gradient Button
</Button>

Vấn đề là khi hover hoặc focus, Ant Design sẽ áp dụng các style mặc định của nó, có thể ghi đè hoặc xung đột với gradient của bạn. Các trạng thái hover/focus/active của Button sẽ làm mất hiệu ứng gradient hoặc gây ra các hiệu ứng không mong muốn.

2. Hạn chế về cấu trúc và hành vi component

2.1. Thay đổi cấu trúc cơ bản của component

Vấn đề: Các component như Modal, Drawer khó thay đổi cấu trúc cơ bản (ví dụ: thay đổi vị trí nút đóng, thay đổi cách hiển thị overlay).

Ví dụ: Tùy chỉnh Modal với footer bên trái và nút tùy chỉnh ở góc trên bên trái

// Ant Design không cung cấp API để dễ dàng thay đổi vị trí footer và thêm nút tùy chỉnh
<Modal
  title="Custom Modal"
  visible={visible}
  onCancel={handleCancel}
  footer={[
    <Button key="back" onClick={handleCancel}>
      Hủy bỏ
    </Button>,
    <Button key="submit" type="primary" onClick={handleOk}>
      Xác nhận
    </Button>,
  ]}
  // Không có prop cho footer trái và nút góc trái
>
  Nội dung modal
</Modal>

Để đặt footer sang trái, bạn cần phải ghi đè CSS hoặc tạo wrapper component phức tạp, cả hai cách đều dễ bị ảnh hưởng khi antd cập nhật.

2.2. Form layout phi tiêu chuẩn

Vấn đề: Form của antd tuân theo bố cục tiêu chuẩn, gặp khó khăn khi cần thiết kế form với bố cục đặc biệt.

Ví dụ: Form với layout phức tạp không chuẩn

// Form với các trường xếp theo kiểu lưới không đều
<Form>
  <Row>
    <Col span={6}><Form.Item name="field1" label="Field 1" /></Col>
    <Col span={10}><Form.Item name="field2" label="Field 2" /></Col>
    <Col span={8}>
      <Row>
        <Col span={12}><Form.Item name="field3" label="Field 3" /></Col>
        <Col span={12}><Form.Item name="field4" label="Field 4" /></Col>
      </Row>
    </Col>
  </Row>
  {/* Form với các section xen kẽ và nhóm field phức tạp */}
  <Divider />
  <section className="special-section">
    <h3>Thông tin đặc biệt</h3>
    <Row gutter={[16, 24]}>
      <Col span={12}>
        <Form.Item
          name="specialField"
          label="Trường đặc biệt"
          // Các validation rule phức tạp
        >
          <Input.TextArea rows={4} />
        </Form.Item>
      </Col>
      <Col span={12}>
        {/* Input group lồng nhau phức tạp */}
        <div className="custom-input-group">
          <Form.Item name="subField1" label="Sub Field 1" noStyle>
            <Input style={{ width: '50%' }} />
          </Form.Item>
          <Form.Item name="subField2" label="Sub Field 2" noStyle>
            <Input style={{ width: '50%' }} />
          </Form.Item>
        </div>
      </Col>
    </Row>
  </section>
</Form>

Form của antd được thiết kế để hoạt động tốt với các layout chuẩn (horizontal, vertical, inline). Khi bạn cần các bố cục phức tạp hơn với nhiều section khác nhau, form lồng nhau, hoặc các nhóm trường hình thức đặc biệt, bạn sẽ gặp khó khăn trong việc duy trì cả styling và functionality (như validation, field dependencies).

2.3. Cấu trúc Bảng phức tạp

Vấn đề: Tùy chỉnh Table cho các cấu trúc hiển thị phức tạp (như bảng lồng nhau, nhóm cột động, hoặc các cell có nội dung đa dạng) rất khó thực hiện.

Ví dụ: Bảng với cấu trúc lồng nhau và cột động

const dynamicColumns = generateDynamicColumns(); // Columns được tạo động từ dữ liệu

// Table với nested structure và dynamic columns
<Table
  columns={[
    {
      title: 'Thông tin',
      children: [
        { title: 'Tên', dataIndex: 'name', key: 'name' },
        { title: 'Tuổi', dataIndex: 'age', key: 'age' },
      ]
    },
    {
      title: 'Metrics',
      children: dynamicColumns // Số lượng cột con thay đổi theo dữ liệu
    },
    {
      title: 'Actions',
      render: (_, record) => (
        // Custom complex cell với nhiều tương tác
        <div className="action-cell">
          <Button type="link" onClick={() => showDetails(record)}>Chi tiết</Button>
          <Dropdown overlay={<Menu>...</Menu>}>
            <Button>Thêm</Button>
          </Dropdown>
          <Progress percent={record.progress} size="small" />
        </div>
      )
    }
  ]}
  dataSource={data}
  expandable={{
    expandedRowRender: record => (
      // Nested table trong expanded row
      <Table
        columns={nestedColumns}
        dataSource={record.children}
        pagination={false}
      />
    )
  }}
/>

Table của antd có thể xử lý các cấu trúc cơ bản, nhưng khi cần các cấu trúc phức tạp như cột động dựa trên dữ liệu, cột lồng nhau nhiều cấp, hoặc các expanded row với nội dung phức tạp, bạn sẽ gặp nhiều khó khăn trong cả việc styling và xử lý logic.

3. Thách thức về thiết kế responsive

3.1. Responsive breakpoints hạn chế

Vấn đề: antd sử dụng các breakpoint cố định, khó điều chỉnh các breakpoint tùy chỉnh cho thiết kế responsive phức tạp.

Ví dụ: Cần breakpoint tùy chỉnh cho layout đặc biệt

// Antd sử dụng breakpoints cố định: xs, sm, md, lg, xl, xxl
<Row>
  <Col xs={24} sm={12} md={8} lg={6} xl={4}>
    Cột 1
  </Col>
  <Col xs={24} sm={12} md={8} lg={6} xl={4}>
    Cột 2
  </Col>
  {/* Không có cách đơn giản để thêm breakpoint tùy chỉnh như 920px */}
</Row>

Nếu thiết kế của bạn yêu cầu breakpoint ở 920px (không phải một trong các breakpoint mặc định của antd), bạn phải xử lý thông qua CSS media queries bên ngoài hệ thống Grid của antd, dẫn đến mã không nhất quán và khó bảo trì.

3.2. Grid system không linh hoạt

Vấn đề: Hệ thống lưới của antd có thể không đủ linh hoạt cho các bố cục grid phức tạp, đặc biệt là khi cần các tỷ lệ cột đặc biệt.

Ví dụ: Grid với tỷ lệ cột không chuẩn

// Grid 14-column với các tỷ lệ đặc biệt (5:9)
// Antd chỉ hỗ trợ hệ thống 24 cột mặc định
<Row>
  <Col span={10}>Column 1</Col> {/* Thực tế muốn 5/14 của width */}
  <Col span={14}>Column 2</Col> {/* Thực tế muốn 9/14 của width */}
</Row>

Antd sử dụng hệ thống 24 cột, nhưng nếu thiết kế của bạn yêu cầu hệ thống grid khác (ví dụ: 14 cột), bạn phải chuyển đổi các giá trị, dẫn đến các số lẻ và không trực quan.

3.3. Component responsive phức tạp

Vấn đề: Các component như Menu, Layout khó tùy chỉnh hành vi responsive khi cần những thay đổi đáng kể giữa các kích thước màn hình.

Ví dụ: Menu responsive phức tạp

// Menu cần thay đổi hoàn toàn cấu trúc và hành vi dựa trên kích thước màn hình
const [screenSize, setScreenSize] = useState(window.innerWidth);
const [menuMode, setMenuMode] = useState('horizontal');

useEffect(() => {
  // Logic phức tạp để xác định menu mode
  if (screenSize > 1024) {
    setMenuMode('horizontal');
  } else if (screenSize > 768) {
    setMenuMode('vertical');
  } else {
    // Trên mobile cần drawer với cấu trúc khác
    setMenuMode('inline');
  }
}, [screenSize]);

return (
  <>
    {screenSize <= 768 ? (
      <Drawer visible={menuVisible} onClose={toggleMenu}>
        <Menu mode="inline">
          {/* Cấu trúc menu mobile */}
          <Menu.Item key="home">Trang chủ - Mobile</Menu.Item>
          <Menu.Item key="special">Mục đặc biệt chỉ hiện trên mobile</Menu.Item>
        </Menu>
      </Drawer>
    ) : (
      <Menu mode={menuMode}>
        {/* Cấu trúc menu desktop/tablet */}
        <Menu.Item key="home">Trang chủ</Menu.Item>
        <SubMenu key="products" title="Sản phẩm">
          {/* Submenu chỉ hiển thị trên desktop/tablet */}
        </SubMenu>
      </Menu>
    )}
    {/* Button hiển thị menu trên mobile */}
    {screenSize <= 768 && (
      <Button onClick={toggleMenu}>
        <MenuOutlined />
      </Button>
    )}
  </>
);

Component Menu của antd hỗ trợ các mode cơ bản (horizontal, vertical, inline), nhưng khi cần các thay đổi phức tạp giữa các kích thước màn hình (như thay đổi hoàn toàn cấu trúc menu hoặc thay đổi các mục menu dựa trên kích thước màn hình), bạn phải viết nhiều mã tùy chỉnh và điều kiện, làm cho code phức tạp và khó bảo trì.

4. Vấn đề về hiệu suất

4.1. Bundle size lớn

Vấn đề: Khi tùy chỉnh nhiều, việc tối ưu bundle size trở nên khó khăn, dẫn đến ứng dụng nặng hơn.

Ví dụ: Import nhiều component và tùy chỉnh chúng

// Mỗi khi tùy chỉnh, bạn thường phải import nhiều component
import { Button, DatePicker, Form, Input, Select, Table, Tabs, Modal, Drawer, Menu } from 'antd';
import { UserOutlined, HomeOutlined, SettingOutlined, ... } from '@ant-design/icons';

// CSS tùy chỉnh cho mỗi component
import './CustomButton.less';
import './CustomTable.less';
import './CustomForm.less';
// ...nhiều file CSS tùy chỉnh khác

Ngay cả với tree-shaking, việc tùy chỉnh nhiều component thường dẫn đến bundle size lớn hơn vì bạn cần import nhiều component và viết nhiều mã CSS tùy chỉnh.

4.2. Render không cần thiết

Vấn đề: Một số component phức tạp như Table, Tree re-render toàn bộ khi chỉ cần thay đổi một phần, gây vấn đề hiệu suất khi tùy chỉnh.

Ví dụ: Re-render không cần thiết với Table lớn

// Re-render problem với Table customization
function ComplexTable() {
  const [data, setData] = useState(largeDataset); // 1000+ rows
  const [selectedRow, setSelectedRow] = useState(null);
  
  // Mỗi lần selectedRow thay đổi, toàn bộ bảng re-render
  return (
    <Table 
      dataSource={data}
      rowClassName={record => record.id === selectedRow ? 'selected-row' : ''}
      columns={[
        {
          title: 'Name',
          dataIndex: 'name',
          render: (text, record) => (
            // Complex custom cell với nhiều thành phần
            <div className="custom-cell">
              <Avatar src={record.avatar} />
              <span>{text}</span>
              {record.id === selectedRow && (
                <Badge status="processing" />
              )}
            </div>
          )
        },
        // ... nhiều cột khác
      ]}
      onRow={record => ({
        onClick: () => setSelectedRow(record.id)
      })}
    />
  );
}

Khi người dùng click vào một hàng, selectedRow thay đổi, khiến toàn bộ component re-render. Table của antd không tối ưu để chỉ re-render các cell bị ảnh hưởng, dẫn đến tình trạng giật lag với dataset lớn.

4.3. Tối ưu hóa virtual scroll

Vấn đề: Khó tùy chỉnh các triển khai virtual scroll cho danh sách lớn khi cần thiết kế đặc biệt.

Ví dụ: Virtual scroll với item phức tạp

// List với virtual scroll và item design phức tạp
<List
  itemLayout="vertical"
  dataSource={largeDataset} // 10,000+ items
  renderItem={item => (
    <List.Item>
      <div className="custom-item-with-animation">
        <div className="item-header">
          <h3>{item.title}</h3>
          <Badge count={item.notificationCount} />
        </div>
        <div className="item-content">
          {/* Nội dung phức tạp với nhiều thành phần */}
          <Descriptions layout="vertical">
            <Descriptions.Item label="Field 1">{item.field1}</Descriptions.Item>
            <Descriptions.Item label="Field 2">{item.field2}</Descriptions.Item>
          </Descriptions>
          <Progress percent={item.progress} />
        </div>
        {/* Custom animations khi item xuất hiện trong viewport */}
      </div>
    </List.Item>
  )}
  pagination={false}
  // Virtual scroll khó tùy chỉnh với item height không cố định
/>

Antd's List không có tích hợp tốt cho virtual scrolling với các item có chiều cao động hoặc các item có thiết kế phức tạp với animation. Để triển khai virtual scroll hiệu quả trong trường hợp này, bạn thường phải sử dụng thư viện bên thứ ba như react-virtualized hoặc react-window và tích hợp thủ công.

5. Giới hạn về animation và transition

5.1. Animation phức tạp

Vấn đề: antd có các animation mặc định đơn giản, khó thực hiện các animation phức tạp hoặc các hiệu ứng chuyển tiếp đặc biệt.

Ví dụ: Carousel với hiệu ứng 3D

// Carousel với hiệu ứng 3D cube không được hỗ trợ sẵn
<Carousel effect="slide"> {/* Không có effect="3d-cube" */}
  <div>
    <h3>Slide 1</h3>
    <img src="image1.jpg" alt="Slide 1" />
  </div>
  <div>
    <h3>Slide 2</h3>
    <img src="image2.jpg" alt="Slide 2" />
  </div>
</Carousel>

Antd Carousel chỉ hỗ trợ các hiệu ứng cơ bản như "fade" và "slide". Khi cần các hiệu ứng phức tạp hơn như 3D cube, card flip, hoặc các hiệu ứng tùy chỉnh, bạn phải dùng thư viện khác hoặc viết CSS/JS phức tạp để override hành vi mặc định.

5.2. Tùy chỉnh đường cong animation

Vấn đề: Khó thay đổi các đường cong timing function của animation mà không ảnh hưởng đến chức năng component.

Ví dụ: Drawer với animation tùy chỉnh

// Drawer với animation tùy chỉnh
<Drawer
  visible={visible}
  onClose={onClose}
  // Không có prop để tùy chỉnh animation timing function
>
  Nội dung drawer
</Drawer>
/* Attempt to customize drawer animation */
.ant-drawer.custom-drawer .ant-drawer-content-wrapper {
  transition: transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) !important;
}

Khi bạn muốn thay đổi timing function của animation Drawer từ linear thành elastic, bạn phải override CSS mặc định, có thể gây ra các vấn đề không mong muốn với tương tác và chức năng.

5.3. Các hiệu ứng đặc biệt

Vấn đề: Hiệu ứng như parallax, morph transitions, 3D transformations khó tích hợp với các component antd.

Ví dụ: Card với hiệu ứng parallax và 3D

// Card với hiệu ứng parallax và 3D tilt
<Card
  className="parallax-card"
  cover={<img alt="example" src="https://example.com/image.jpg" />}
  // Không có prop cho hiệu ứng đặc biệt
>
  <Card.Meta
    title="Card title"
    description="This is the description"
  />
</Card>
// Custom JS cần thiết cho hiệu ứng 3D tilt
useEffect(() => {
  const card = document.querySelector('.parallax-card');
  
  const handleMouseMove = (e) => {
    const rect = card.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const y = e.clientY - rect.top;
    
    const centerX = rect.width / 2;
    const centerY = rect.height / 2;
    
    const rotateX = (y - centerY) / 10;
    const rotateY = (centerX - x) / 10;
    
    card.style.transform = `perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`;
  };
  
  card.addEventListener('mousemove', handleMouseMove);
  card.addEventListener('mouseleave', () => {
    card.style.transform = 'perspective(1000px) rotateX(0) rotateY(0)';
  });
  
  return () => {
    card.removeEventListener('mousemove', handleMouseMove);
    card.removeEventListener('mouseleave', () => {});
  };
}, []);

Để thêm hiệu ứng 3D tilt vào Card, bạn phải viết mã JavaScript tùy chỉnh và CSS phức tạp. Antd không cung cấp API cho các hiệu ứng nâng cao này, và tích hợp chúng có thể gây xung đột với các animation mặc định.

6. Tùy chỉnh về accessibility (a11y)

6.1. Điều chỉnh trình đọc màn hình

Vấn đề: Khó tùy chỉnh thông báo và hành vi của trình đọc màn hình cho các trường hợp đặc biệt.

Ví dụ: Form với các thông báo accessibility tùy chỉnh

// Form với các thông báo accessibility tùy chỉnh
<Form>
  <Form.Item
    label="Username"
    name="username"
    // Khó tùy chỉnh thông báo accessibility khi validation thất bại
  >
    <Input />
  </Form.Item>
  
  <Form.Item
    label="Custom Field"
    name="customField"
    // Cần thông báo custom cho screen reader khi field thay đổi
  >
    <Select>
      <Select.Option value="option1">Option 1</Select.Option>
      <Select.Option value="option2">Option 2</Select.Option>
    </Select>
  </Form.Item>
  
  <Button type="primary" htmlType="submit">
    Submit
  </Button>
</Form>

Antd không cung cấp API đầy đủ để tùy chỉnh các thông báo ARIA và hành vi của trình đọc màn hình cho các tình huống phức tạp, như thông báo tùy chỉnh khi validation thất bại hoặc khi dữ liệu form thay đổi theo cách đặc biệt.

6.2. Tuần tự tab tùy chỉnh

Vấn đề: Kiểm soát thứ tự tab phức tạp trong các form hoặc layout tùy chỉnh có thể gặp khó khăn.

Ví dụ: Form với thứ tự tab logic khác với thứ tự hiển thị

// Form với thứ tự tab khác thứ tự hiển thị trực quan
<Form>
  <div className="form-section">
    <Form.Item name="field1" label="Field 1" tabIndex={3} /> 
    <Form.Item name="field2" label="Field 2" tabIndex={1} />
    <Form.Item name="field3" label="Field 3" tabIndex={2} />
  </div>
  
  <div className="form-section">
    {/* Form phức tạp với nhiều section và logic tabbing tùy chỉnh */}
    <Form.Item name="field4" label="Field 4" tabIndex={6} />
    <Form.Item name="field5" label="Field 5" tabIndex={4} />
    <Form.Item name="field6" label="Field 6" tabIndex={5} />
  </div>
</Form>

Mặc dù bạn có thể đặt thuộc tính tabIndex cho các Form.Item, việc quản lý thứ tự tab phức tạp trên toàn bộ ứng dụng, đặc biệt là khi có nhiều phần của form với các logic tab phụ thuộc vào ngữ cảnh, rất khó khăn với API của antd.

6.3. States focus/hover đặc biệt

Vấn đề: Khó tùy chỉnh các trạng thái focus, hover tuân thủ WCAG mà không ảnh hưởng đến hành vi mặc định.

Ví dụ: Button với focus state đặc biệt

// Button với focus state đặc biệt (glow effect + outline tùy chỉnh)
<Button className="custom-focus-button">
  Click me
</Button>
/* CSS for custom focus state */
.custom-focus-button:focus {
  box-shadow: 0 0 0 3px rgba(24, 144, 255, 0.5);
  outline: none;
}

/* Nếu bạn thay đổi outline, bạn phải thay thế bằng giải pháp khác cho a11y */
.custom-focus-button:focus-visible {
  outline: 2px solid #1890ff;
  outline-offset: 2px;
}

Khi tùy chỉnh trạng thái focus, bạn phải đảm bảo tuân thủ các tiêu chuẩn WCAG về độ tương phản và khả năng hiển thị, đồng thời không làm mất các chức năng a11y quan trọng. Antd không cung cấp API rõ ràng để tùy chỉnh những trạng thái này mà vẫn duy trì khả năng tiếp cận.

7. Các component đặc biệt

7.1. Biểu đồ phức tạp

Vấn đề: antd không cung cấp giải pháp tích hợp cho các biểu đồ tùy chỉnh cao.

Ví dụ: Biểu đồ tương tác phức tạp

// Cần tích hợp thư viện biểu đồ riêng biệt
import { Line, Bar, Pie } from '@ant-design/charts'; // Thư viện riêng biệt, không phải core antd

function ComplexDashboard() {
  return (
    <div className="dashboard">
      <Line
        data={lineData}
        xField="date"
        yField="value"
        // Các tùy chỉnh phức tạp
      />
      
      <Bar
        data={barData}
        xField="category"
        yField="value"
        // Tích hợp với UI antd có thể phức tạp
      />
      
      {/* Tích hợp với component khác của antd có thể khó khăn */}
      <Card>
        <Pie
          data={pieData}
          angleField="value"
          colorField="type"
        />
      </Card>
    </div>
  );
}

Antd core không có component biểu đồ tích hợp. Mặc dù có @ant-design/charts, nhưng đây là thư viện riêng biệt và có thể gặp khó khăn khi tích hợp liền mạch với các component core và theme của antd.

7.2. Maps và visualizations

Vấn đề: Không có hỗ trợ tích hợp cho bản đồ, heatmaps và các visualizations phức tạp khác.

Ví dụ: Tích hợp bản đồ với giao diện antd

// Cần tích hợp thư viện bản đồ riêng biệt
import { Map, Marker } from 'react-map-gl';
import { Card, Select, Button } from 'antd';

function LocationSelector() {
  return (
    <Card title="Chọn địa điểm">
      <div className="map-container">
        <Map
          initialViewState={{
            longitude: 105.85,
            latitude: 21.03,
            zoom: 12
          }}
          style={{width: '100%', height: 400}}
          mapStyle="mapbox://styles/mapbox/streets-v11"
        >
          <Marker longitude={105.85} latitude={21.03} />
          {/* Custom markers, layers, etc. */}
        </Map>
      </div>
      
      <div className="location-controls">
        <Select
          placeholder="Chọn khu vực"
          options={areaOptions}
          style={{ width: '100%', marginBottom: 16 }}
        />
        
        <Button type="primary">Xác nhận địa điểm</Button>
      </div>
    </Card>
  );
}

Tích hợp các thư viện bản đồ như Mapbox, Google Maps hoặc Leaflet với antd đòi hỏi nhiều công sức để đảm bảo phong cách nhất quán và tương tác liền mạch giữa các control bản đồ và component antd.

7.3. Rich text editors

Vấn đề: Không có component tích hợp cho trình soạn thảo văn bản phong phú.

Ví dụ: Tích hợp rich text editor với form antd

// Cần tích hợp thư viện editor riêng biệt
import { Editor } from 'draft-js';
import { Form, Button, Card } from 'antd';
import 'draft-js/dist/Draft.css';

function BlogPostForm() {
  const [editorState, setEditorState] = useState(() => EditorState.createEmpty());
  
  const handleSubmit = (values) => {
    // Chuyển đổi nội dung editor thành HTML/JSON
    const contentState = editorState.getCurrentContent();
    const contentHTML = stateToHTML(contentState);
    
    // Gửi form với dữ liệu từ cả antd Form và editor
    const formData = {
      ...values,
      content: contentHTML
    };
    
    console.log(formData);
  };
  
  return (
    <Form onFinish={handleSubmit}>
      <Form.Item name="title" label="Tiêu đề" rules={[{ required: true }]}>
        <Input />
      </Form.Item>
      
      <Form.Item label="Nội dung" required>
        <Card bordered={false} className="editor-card">
          <Editor
            editorState={editorState}
            onChange={setEditorState}
            // Khó styling để match với antd design
          />
        </Card>
        {/* Antd Form không tích hợp trực tiếp với Draft.js */}
      </Form.Item>
      
      <Form.Item>
        <Button type="primary" htmlType="submit">
          Đăng bài
        </Button>
      </Form.Item>
    </Form>
  );
}

Tích hợp rich text editor như Draft.js, Slate, hoặc Quill với Form của antd yêu cầu nhiều mã tùy chỉnh để xử lý validation, dữ liệu form, và styling nhất quán.

7.4. Complex media players

Vấn đề: Thiếu các component cho trình phát media tùy chỉnh cao.

Ví dụ: Tích hợp video player với giao diện antd

// Cần tích hợp thư viện media player riêng biệt
import ReactPlayer from 'react-player';
import { Card, Slider, Button, Space } from 'antd';
import { PlayCircleOutlined, PauseCircleOutlined } from '@ant-design/icons';

function CustomVideoPlayer() {
  const [playing, setPlaying] = useState(false);
  const [progress, setProgress] = useState(0);
  const playerRef = useRef(null);
  
  const handleProgress = (state) => {
    setProgress(state.played * 100);
  };
  
  const handleSeek = (value) => {
    setProgress(value);
    playerRef.current.seekTo(value / 100);
  };
  
  return (
    <Card>
      <div className="player-container">
        <ReactPlayer
          ref={playerRef}
          url="https://example.com/video.mp4"
          playing={playing}
          width="100%"
          height="auto"
          onProgress={handleProgress}
          // Styling không match với antd design
        />
      </div>
      
      <div className="player-controls">
        <Space>
          <Button
            type="text"
            icon={playing ? <PauseCircleOutlined /> : <PlayCircleOutlined />}
            onClick={() => setPlaying(!playing)}
          />
          
          <Slider
            value={progress}
            onChange={handleSeek}
            style={{ width: 300, marginLeft: 16 }}
          />
        </Space>
      </div>
    </Card>
  );
}

Tích hợp các trình phát media như video player hoặc audio player với giao diện antd yêu cầu nhiều công sức để đảm bảo điều khiển player khớp với design system, và xử lý các tương tác phức tạp như timeline, subtitles, hoặc các tùy chọn chất lượng.

8. Kết luận và khuyến nghị

8.1. Tóm tắt các hạn chế chính

Ant Design là một thư viện UI mạnh mẽ cho React, nhưng gặp hạn chế trong các trường hợp:

  1. Yêu cầu thiết kế tùy chỉnh cao với nhiều thay đổi từ design system mặc định
  2. Cấu trúc component phức tạp với nhiều lớp lồng nhau
  3. Responsive design với các breakpoint và hành vi tùy chỉnh
  4. Hiệu suất với dataset lớn và tương tác phức tạp
  5. Animation và hiệu ứng nâng cao
  6. Accessibility tùy chỉnh cao
  7. Các component đặc biệt như biểu đồ, bản đồ, rich text editor

8.2. Giải pháp thay thế

Khi gặp các hạn chế của Ant Design, có thể xem xét các giải pháp sau:

  1. Kết hợp với thư viện CSS-in-JS

    • Sử dụng styled-components hoặc emotion để tùy chỉnh style mà không ảnh hưởng đến cấu trúc component
    • Ví dụ: const StyledButton = styled(Button)... với nhiều tùy chỉnh CSS
  2. Tạo component wrapper

    • Đóng gói component antd trong component tùy chỉnh để thêm chức năng hoặc style
    • Giữ API tương thích với antd nhưng thêm các tùy chỉnh cần thiết
  3. Sử dụng thư viện chuyên biệt cho các component đặc biệt

    • Biểu đồ: recharts, visx, echarts, d3
    • Map: react-map-gl, google-map-react, react-leaflet
    • Rich text: Draft.js, Slate, Quill
    • Media: react-player, video.js
  4. Xây dựng component từ đầu cho các trường hợp đặc biệt

    • Một số trường hợp, xây dựng component từ đầu có thể hiệu quả hơn việc tùy chỉnh component antd
    • Kết hợp các primitive component của antd như Button, Input với cấu trúc tùy chỉnh
  5. Sử dụng kết hợp antd với thư viện khác

    • Headless UI libraries (radix-ui, react-aria) cho accessibility tốt hơn
    • Component animation (framer-motion, react-spring) cho các hiệu ứng nâng cao

8.3. Các thực hành tốt nhất khi sử dụng Ant Design

  1. Hiểu rõ hệ thống thiết kế của bạn trước khi chọn thư viện

    • Đánh giá xem thiết kế của bạn có phù hợp với design system của Ant Design không
    • Xác định các điểm cần tùy chỉnh từ sớm
  2. Xây dựng component library riêng dựa trên antd

    • Tạo các component wrapper để đồng nhất hóa các tùy chỉnh trong toàn bộ dự án
    • Tạo tài liệu rõ ràng về các component tùy chỉnh
  3. Kết hợp các cách tiếp cận

    • Sử dụng antd cho các component cơ bản
    • Sử dụng thư viện chuyên biệt cho các component phức tạp
    • Xây dựng component tùy chỉnh khi cần thiết
  4. Tối ưu hóa hiệu suất từ đầu

    • Sử dụng React.memo, useMemo, và useCallback cho các component phức tạp
    • Tránh re-render không cần thiết bằng cách tái cấu trúc component tree
  5. Thiết lập quy trình kiểm tra a11y

    • Sử dụng các công cụ như axe, lighthouse để đảm bảo accessibility
    • Kiểm tra với screen reader và keyboard navigation

Bằng cách kết hợp Ant Design với các giải pháp tùy chỉnh phù hợp, bạn có thể tận dụng sức mạnh của thư viện này đồng thời vượt qua các hạn chế của nó để đáp ứng các yêu cầu thiết kế tùy chỉnh cao.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment