1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Use react.memo for table rows

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>
This commit is contained in:
Alex Andreev 2022-03-23 14:41:58 +03:00
parent 692c2ab88c
commit ec66744ca3
4 changed files with 100 additions and 53 deletions

View File

@ -9,8 +9,8 @@ import React, { ReactNode } from "react";
import { computed, makeObservable } from "mobx";
import { Observer, observer } from "mobx-react";
import { ConfirmDialog, ConfirmDialogParams } from "../confirm-dialog";
import { Table, TableCell, TableCellProps, TableHead, TableProps, TableRow, TableRowProps, TableSortCallbacks } from "../table";
import { boundMethod, cssNames, IClassName, isReactNode, prevDefault, stopPropagation } from "../../utils";
import { Table, TableCell, TableCellProps, TableHead, TableProps, TableRowProps, TableSortCallbacks } from "../table";
import { boundMethod, cssNames, IClassName, prevDefault, stopPropagation } from "../../utils";
import { AddRemoveButtons, AddRemoveButtonsProps } from "../add-remove-buttons";
import { NoItems } from "../no-items";
import { Spinner } from "../spinner";
@ -21,6 +21,7 @@ import { MenuActions } from "../menu/menu-actions";
import { MenuItem } from "../menu";
import { Checkbox } from "../checkbox";
import { UserStore } from "../../../common/user-store";
import { Row } from "./row";
export interface ItemListLayoutContentProps<I extends ItemObject> {
getFilters: () => Filter[];
@ -75,66 +76,43 @@ export class ItemListLayoutContent<I extends ItemObject> extends React.Component
getTableRow(item: I) {
const {
isSelectable, renderTableHeader, renderTableContents, renderItemMenu,
renderTableHeader, renderTableContents, renderItemMenu,
store, hasDetailsView, onDetails,
copyClassNameFromHeadCells, customizeTableRowProps, detailsItem,
customizeTableRowProps, detailsItem, isSelectable,
} = this.props;
const { isSelected } = store;
const selected = detailsItem && detailsItem.getId() === item.getId();
const onCheckboxChange = isSelectable ? prevDefault(() => store.toggleSelection(item)) : null;
const itemMenu = renderItemMenu && (
<TableCell className="menu">
<div onClick={stopPropagation}>
{renderItemMenu(item, store)}
</div>
</TableCell>
);
return (
<TableRow
nowrap
searchItem={item}
sortItem={item}
selected={detailsItem && detailsItem.getId() === item.getId()}
<Row
selected={selected}
checked={isSelected(item)}
renderTableHeader={renderTableHeader}
cells={renderTableContents}
itemMenu={itemMenu}
onCheckboxChange={onCheckboxChange}
onClick={hasDetailsView ? prevDefault(() => onDetails(item)) : undefined}
item={item}
showColumn={this.showColumn}
{...customizeTableRowProps(item)}
>
{isSelectable && (
<TableCell
checkbox
isChecked={isSelected(item)}
onClick={prevDefault(() => store.toggleSelection(item))}
/>
)}
{renderTableContents(item).map((content, index) => {
const cellProps: TableCellProps = isReactNode(content)
? { children: content }
: content;
const headCell = renderTableHeader?.[index];
if (copyClassNameFromHeadCells && headCell) {
cellProps.className = cssNames(
cellProps.className,
headCell.className,
);
}
if (!headCell || this.showColumn(headCell)) {
return <TableCell key={index} {...cellProps} />;
}
return null;
})}
{renderItemMenu && (
<TableCell className="menu">
<div onClick={stopPropagation}>
{renderItemMenu(item, store)}
</div>
</TableCell>
)}
</TableRow>
/>
);
}
@boundMethod
getRow(uid: string) {
getRow(uid: string, item: I) {
return (
<div key={uid}>
<Observer>
{() => {
const item = this.props.getItems().find(item => item.getId() === uid);
if (!item) return null;
return this.getTableRow(item);
@ -202,7 +180,7 @@ export class ItemListLayoutContent<I extends ItemObject> extends React.Component
return null;
}
return this.props.getItems().map(item => this.getRow(item.getId()));
return this.props.getItems().map(item => this.getRow(item.getId(), item));
}
renderTableHeader() {
@ -285,11 +263,11 @@ export class ItemListLayoutContent<I extends ItemObject> extends React.Component
);
}
showColumn({ id: columnId, showWithColumn }: TableCellProps): boolean {
showColumn = ({ id: columnId, showWithColumn }: TableCellProps): boolean => {
const { tableId, isConfigurable } = this.props;
return !isConfigurable || !UserStore.getInstance().isTableColumnHidden(tableId, columnId, showWithColumn);
}
};
renderColumnVisibilityMenu() {
const { renderTableHeader, tableId } = this.props;

View File

@ -0,0 +1,69 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import React, { memo, ReactNode } from "react";
import { cssNames, isReactNode } from "../../utils";
import { TableCell, TableCellProps, TableRow } from "../table";
import type { ItemObject } from "../../../common/item.store";
interface RowProps<I extends ItemObject> {
selected: boolean;
checked?: boolean;
renderTableHeader?: TableCellProps[];
cells: (item: I) => (ReactNode | TableCellProps)[];
itemMenu?: ReactNode;
onCheckboxChange?: (evt: any) => void;
onClick?: (evt: React.MouseEvent) => void;
item: I;
showColumn?: ({ id: columnId, showWithColumn }: TableCellProps) => boolean;
}
export const Row = memo(<I extends ItemObject>({
selected,
checked,
renderTableHeader,
cells,
itemMenu,
onCheckboxChange,
onClick,
item,
showColumn,
...rest
}: RowProps<I>) => {
return (
<TableRow
nowrap
searchItem={item}
sortItem={item}
selected={selected}
onClick={onClick}
{...rest}
>
{onCheckboxChange && (
<TableCell
checkbox
isChecked={checked}
onClick={onCheckboxChange}
/>
)}
{cells(item).map((content, index) => {
const cellProps: TableCellProps = isReactNode(content) ? { children: content } : content;
const headCell = renderTableHeader?.[index];
if (headCell) {
cellProps.className = cssNames(cellProps.className, headCell.className);
}
if (!headCell || showColumn(headCell)) {
return <TableCell key={index} {...cellProps} />;
}
return null;
})}
{itemMenu}
</TableRow>
);
});

View File

@ -67,7 +67,7 @@ export interface TableProps<Item> extends React.DOMAttributes<HTMLDivElement> {
*/
rowLineHeight?: number;
customRowHeights?: (item: Item, lineHeight: number, paddings: number) => number;
getTableRow?: (uid: string) => React.ReactElement<TableRowProps>;
getTableRow?: (uid: string, item?: Item) => React.ReactElement<TableRowProps>;
renderRow?: (item: Item) => React.ReactElement<TableRowProps>;
}

View File

@ -134,7 +134,7 @@ export class VirtualList extends Component<VirtualListProps, State> {
interface RowData {
items: ItemObject[];
getRow?: (uid: string | number) => React.ReactElement<TableRowProps>;
getRow?: (uid: string | number, item?: ItemObject) => React.ReactElement<TableRowProps>;
}
export interface RowProps extends ListChildComponentProps {
@ -146,7 +146,7 @@ const Row = observer((props: RowProps) => {
const { items, getRow } = data;
const item = items[index];
const uid = typeof item == "string" ? index : items[index].getId();
const row = getRow(uid);
const row = getRow(uid, item);
if (!row) return null;