scenario

After the project is deployed to the site, the relative performance of the site client is poor. When antD forms are used, the performance is particularly poor when data is multi-time, and scrolling pages will be particularly slow.

The screening process

1. Monitor performance and find out the culprit that affects performance

Use the console’s Performance to monitor Performance and see what affects Performance when the page scrolls, as shown in the following figure:

As can be seen, the page monitor scrolls for 6+ seconds, and script parsing is performed for 4+ seconds. There are a large number of Mouse events and function calls that need to be executed in the JS thread, which will seriously block the rendering thread. This is where the problem appears. If you do not understand the JS event loop mechanism, you can take a look at this js event loop mechanism

2. Read the source code to find the source code

Rc-table (antD Table, antD Table, antD Table)

.import RcTable, { Summary } from 'rc-table'; .return  <RcTable<RecordType>
          ...
        />
 ...
Copy the code

Rc-table cell source code:

.// ====================== Hover =======================
  const onMouseEnter: React.MouseEventHandler<HTMLTableCellElement> = event= > {
    if (record) {
      onHover(index, index + mergedRowSpan - 1); } additionalProps? .onMouseEnter? .(event); };const onMouseLeave: React.MouseEventHandler<HTMLTableCellElement> = event= > {
    if (record) {
      onHover(-1, -1);
    }

    additionalProps?.onMouseLeave?.(event);
  };
...
Copy the code

The onMouseEnter and onMouseLeave methods are built into each cell of the table. These methods execute onHover.

.const onHover = React.useCallback((start: number, end: number) = >{ setStartRow(start); setEndRow(end); } []);const hoverContext = React.useMemo(
    () = >({ startRow, endRow, onHover }), [onHover, startRow, endRow], ); .return <HoverContext.Provider value={hoverContext}>{bodyNode}</HoverContext.Provider>; .Copy the code

OnHover is the state of the hoverContext component, and it is the state of the hoverContext component.


function Cell<RecordType extends DefaultRecordType> (
  {
    const componentProps: React.TdHTMLAttributes<HTMLTableCellElement> & {
    ...
    className: classNames(
      cellPrefixCls,
      className,
      {
        ...
        [`${cellPrefixCls}-row-hover`] :! cellProps && hovering, }, ... ) . };return( <Component {... componentProps}> {appendNode} {childNode} </Component> ); }const WrappedCell = React.forwardRef((props: CellProps<any>, ref: React.Ref<any>) => {
  const{ onHover, startRow, endRow } = React.useContext(HoverContext); .const hovering = inHoverRange(index, mergedRowSpan || 1, startRow, endRow);
  
  return( <MemoCell ... onHover={onHover} /> ); }); .export default WrappedCell;

Copy the code

It can be seen that onHover finally adds a className to the Cell where the mouse is hovering, thus triggering the style change. We can experiment, after the hover Cell is sure to add a new className, as shown in the figure:

By now, the root cause of poor performance has been found, and it is also found that these redundant Mouse events do not have much effect, but seriously affect the performance, so I try to remove them.

The solution

Using the components property in ANTD’s Table will customize the cell, preventing onMouseEnter, onMouseLeave pass-through, and improving Table scrolling performance by 3 times.


// Note that TdCell refers to the DataTable out-of-scope declaration
const TdCell = (props: any) = > {
  // onMouseEnter, onMouseLeave will severely block table cell rendering when there is a large amount of data, which seriously affects performance
  const{ onMouseEnter, onMouseLeave, ... restProps } = props;return <td {. restProps} / >;
};

const DataTable: React.FC<tableType> = (props) = > {
  const { columns,dataSource } = props;
  return <Table 
          columns={columns} 
          dataSource={dataSource} 
          components={{
              body: { cell: TdCell}}} / >
  );
};

export default DataTable;

Copy the code

After the configuration, monitor performance again.

Problem solved!