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:
parent
692c2ab88c
commit
ec66744ca3
@ -9,8 +9,8 @@ import React, { ReactNode } from "react";
|
|||||||
import { computed, makeObservable } from "mobx";
|
import { computed, makeObservable } from "mobx";
|
||||||
import { Observer, observer } from "mobx-react";
|
import { Observer, observer } from "mobx-react";
|
||||||
import { ConfirmDialog, ConfirmDialogParams } from "../confirm-dialog";
|
import { ConfirmDialog, ConfirmDialogParams } from "../confirm-dialog";
|
||||||
import { Table, TableCell, TableCellProps, TableHead, TableProps, TableRow, TableRowProps, TableSortCallbacks } from "../table";
|
import { Table, TableCell, TableCellProps, TableHead, TableProps, TableRowProps, TableSortCallbacks } from "../table";
|
||||||
import { boundMethod, cssNames, IClassName, isReactNode, prevDefault, stopPropagation } from "../../utils";
|
import { boundMethod, cssNames, IClassName, prevDefault, stopPropagation } from "../../utils";
|
||||||
import { AddRemoveButtons, AddRemoveButtonsProps } from "../add-remove-buttons";
|
import { AddRemoveButtons, AddRemoveButtonsProps } from "../add-remove-buttons";
|
||||||
import { NoItems } from "../no-items";
|
import { NoItems } from "../no-items";
|
||||||
import { Spinner } from "../spinner";
|
import { Spinner } from "../spinner";
|
||||||
@ -21,6 +21,7 @@ import { MenuActions } from "../menu/menu-actions";
|
|||||||
import { MenuItem } from "../menu";
|
import { MenuItem } from "../menu";
|
||||||
import { Checkbox } from "../checkbox";
|
import { Checkbox } from "../checkbox";
|
||||||
import { UserStore } from "../../../common/user-store";
|
import { UserStore } from "../../../common/user-store";
|
||||||
|
import { Row } from "./row";
|
||||||
|
|
||||||
export interface ItemListLayoutContentProps<I extends ItemObject> {
|
export interface ItemListLayoutContentProps<I extends ItemObject> {
|
||||||
getFilters: () => Filter[];
|
getFilters: () => Filter[];
|
||||||
@ -75,66 +76,43 @@ export class ItemListLayoutContent<I extends ItemObject> extends React.Component
|
|||||||
|
|
||||||
getTableRow(item: I) {
|
getTableRow(item: I) {
|
||||||
const {
|
const {
|
||||||
isSelectable, renderTableHeader, renderTableContents, renderItemMenu,
|
renderTableHeader, renderTableContents, renderItemMenu,
|
||||||
store, hasDetailsView, onDetails,
|
store, hasDetailsView, onDetails,
|
||||||
copyClassNameFromHeadCells, customizeTableRowProps, detailsItem,
|
customizeTableRowProps, detailsItem, isSelectable,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const { isSelected } = store;
|
const { isSelected } = store;
|
||||||
|
const selected = detailsItem && detailsItem.getId() === item.getId();
|
||||||
return (
|
const onCheckboxChange = isSelectable ? prevDefault(() => store.toggleSelection(item)) : null;
|
||||||
<TableRow
|
const itemMenu = renderItemMenu && (
|
||||||
nowrap
|
|
||||||
searchItem={item}
|
|
||||||
sortItem={item}
|
|
||||||
selected={detailsItem && detailsItem.getId() === item.getId()}
|
|
||||||
onClick={hasDetailsView ? prevDefault(() => onDetails(item)) : undefined}
|
|
||||||
{...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">
|
<TableCell className="menu">
|
||||||
<div onClick={stopPropagation}>
|
<div onClick={stopPropagation}>
|
||||||
{renderItemMenu(item, store)}
|
{renderItemMenu(item, store)}
|
||||||
</div>
|
</div>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
)}
|
);
|
||||||
</TableRow>
|
|
||||||
|
return (
|
||||||
|
<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)}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@boundMethod
|
@boundMethod
|
||||||
getRow(uid: string) {
|
getRow(uid: string, item: I) {
|
||||||
return (
|
return (
|
||||||
<div key={uid}>
|
<div key={uid}>
|
||||||
<Observer>
|
<Observer>
|
||||||
{() => {
|
{() => {
|
||||||
const item = this.props.getItems().find(item => item.getId() === uid);
|
|
||||||
|
|
||||||
if (!item) return null;
|
if (!item) return null;
|
||||||
|
|
||||||
return this.getTableRow(item);
|
return this.getTableRow(item);
|
||||||
@ -202,7 +180,7 @@ export class ItemListLayoutContent<I extends ItemObject> extends React.Component
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.props.getItems().map(item => this.getRow(item.getId()));
|
return this.props.getItems().map(item => this.getRow(item.getId(), item));
|
||||||
}
|
}
|
||||||
|
|
||||||
renderTableHeader() {
|
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;
|
const { tableId, isConfigurable } = this.props;
|
||||||
|
|
||||||
return !isConfigurable || !UserStore.getInstance().isTableColumnHidden(tableId, columnId, showWithColumn);
|
return !isConfigurable || !UserStore.getInstance().isTableColumnHidden(tableId, columnId, showWithColumn);
|
||||||
}
|
};
|
||||||
|
|
||||||
renderColumnVisibilityMenu() {
|
renderColumnVisibilityMenu() {
|
||||||
const { renderTableHeader, tableId } = this.props;
|
const { renderTableHeader, tableId } = this.props;
|
||||||
|
|||||||
69
src/renderer/components/item-object-list/row.tsx
Normal file
69
src/renderer/components/item-object-list/row.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
});
|
||||||
@ -67,7 +67,7 @@ export interface TableProps<Item> extends React.DOMAttributes<HTMLDivElement> {
|
|||||||
*/
|
*/
|
||||||
rowLineHeight?: number;
|
rowLineHeight?: number;
|
||||||
customRowHeights?: (item: Item, lineHeight: number, paddings: number) => 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>;
|
renderRow?: (item: Item) => React.ReactElement<TableRowProps>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -134,7 +134,7 @@ export class VirtualList extends Component<VirtualListProps, State> {
|
|||||||
|
|
||||||
interface RowData {
|
interface RowData {
|
||||||
items: ItemObject[];
|
items: ItemObject[];
|
||||||
getRow?: (uid: string | number) => React.ReactElement<TableRowProps>;
|
getRow?: (uid: string | number, item?: ItemObject) => React.ReactElement<TableRowProps>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RowProps extends ListChildComponentProps {
|
export interface RowProps extends ListChildComponentProps {
|
||||||
@ -146,7 +146,7 @@ const Row = observer((props: RowProps) => {
|
|||||||
const { items, getRow } = data;
|
const { items, getRow } = data;
|
||||||
const item = items[index];
|
const item = items[index];
|
||||||
const uid = typeof item == "string" ? index : items[index].getId();
|
const uid = typeof item == "string" ? index : items[index].getId();
|
||||||
const row = getRow(uid);
|
const row = getRow(uid, item);
|
||||||
|
|
||||||
if (!row) return null;
|
if (!row) return null;
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user