Skip to content

Commit

Permalink
fix: Memoize virtualized renderer (#28372)
Browse files Browse the repository at this point in the history
* fix: Memoize virtualized renderer

Memoizes the virtualized renderer to avoid react-window mounting
continously. Also updates the example to memoize the row renderer.

* changefile

* update md

* pr suggestions
  • Loading branch information
ling1726 authored Jun 30, 2023
1 parent 7ad45a9 commit 1745a0b
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 26 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "fix: Memoize virtualized renderer",
"packageName": "@fluentui/react-data-grid-react-window",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export type DataGridBodyProps<TItem = unknown> = Omit<DataGridBodyProps_2, 'chil
itemSize: number;
height: number;
width?: string | number;
children: RowRenderFunction<TItem>;
children: RowRenderer<TItem>;
ariaRowIndexStart?: number;
};

Expand All @@ -59,6 +59,9 @@ export { DataGridSelectionCell }

export { DataGridSelectionCellProps }

// @public (undocumented)
export type RowRenderer<TItem = unknown> = (row: TableRowData<TItem>, style: React_2.CSSProperties) => React_2.ReactNode;

// (No @packageDocumentation comment for this package)

```
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,11 @@ import type {
DataGridBodySlots as DataGridBodySlotsBase,
DataGridBodyState as DataGridBodyStateBase,
} from '@fluentui/react-table';
import { ListChildComponentProps } from 'react-window';

export type DataGridBodySlots = DataGridBodySlotsBase;

export type RowRenderFunction<TItem = unknown> = (
row: TableRowData<TItem>,
style: React.CSSProperties,
) => React.ReactNode;
export type RowRenderer<TItem = unknown> = (row: TableRowData<TItem>, style: React.CSSProperties) => React.ReactNode;

/**
* DataGridBody Props
Expand All @@ -33,7 +31,7 @@ export type DataGridBodyProps<TItem = unknown> = Omit<DataGridBodyPropsBase, 'ch
/**
* Children render function for rows
*/
children: RowRenderFunction<TItem>;
children: RowRenderer<TItem>;
/**
* All virtualized rows must have the [aria-rowindex](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-rowindex)
* attribute for correct screen reader navigation. The default start index is 2 since we assume that there is only
Expand All @@ -49,5 +47,5 @@ export type DataGridBodyProps<TItem = unknown> = Omit<DataGridBodyPropsBase, 'ch
export type DataGridBodyState = Omit<DataGridBodyStateBase, 'renderRow'> &
Pick<DataGridBodyProps, 'itemSize' | 'height'> &
Pick<Required<DataGridBodyProps>, 'width' | 'ariaRowIndexStart'> & {
renderRow: RowRenderFunction;
virtualizedRow: (props: ListChildComponentProps) => React.ReactElement;
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@
import { createElement } from '@fluentui/react-jsx-runtime';
import { getSlotsNext } from '@fluentui/react-utilities';
import type { DataGridBodyState, DataGridBodySlots } from './DataGridBody.types';
import { FixedSizeList as List, ListChildComponentProps } from 'react-window';
import { TableRowData, TableRowIdContextProvider } from '@fluentui/react-table';
import { TableRowIndexContextProvider } from '../../contexts/rowIndexContext';
import { FixedSizeList as List } from 'react-window';

/**
* Render the final JSX of DataGridVirtualizedBody
Expand All @@ -23,14 +21,7 @@ export const renderDataGridBody_unstable = (state: DataGridBodyState) => {
height={state.height}
itemCount={state.rows.length}
>
{({ data, index, style }: ListChildComponentProps) => {
const row: TableRowData<unknown> = data[index];
return (
<TableRowIndexContextProvider value={state.ariaRowIndexStart + index}>
<TableRowIdContextProvider value={row.rowId}>{state.renderRow(row, style)}</TableRowIdContextProvider>
</TableRowIndexContextProvider>
);
}}
{state.virtualizedRow}
</List>
</slots.root>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import * as React from 'react';
import type { DataGridBodyProps, DataGridBodyState } from './DataGridBody.types';
import { useDataGridBody_unstable as useDataGridBodyBase_unstable, RowRenderFunction } from '@fluentui/react-table';
import {
useDataGridBody_unstable as useDataGridBodyBase_unstable,
RowRenderFunction,
TableRowData,
TableRowIdContextProvider,
} from '@fluentui/react-table';
import { TableRowIndexContextProvider } from '../../contexts/rowIndexContext';

/**
* Create the state required to render DataGridBody.
Expand All @@ -18,11 +24,23 @@ export const useDataGridBody_unstable = (props: DataGridBodyProps, ref: React.Re
const renderRowWithUnknown = children as RowRenderFunction;
const baseState = useDataGridBodyBase_unstable({ ...props, children: renderRowWithUnknown }, ref);

const virtualizedRow: DataGridBodyState['virtualizedRow'] = React.useCallback(
({ data, index, style }) => {
const row: TableRowData<unknown> = data[index];
return (
<TableRowIndexContextProvider value={ariaRowIndexStart + index}>
<TableRowIdContextProvider value={row.rowId}>{children(row, style)}</TableRowIdContextProvider>
</TableRowIndexContextProvider>
);
},
[ariaRowIndexStart, children],
);

return {
...baseState,
itemSize,
height,
renderRow: children,
virtualizedRow,
width,
ariaRowIndexStart,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ export type {
DataGridProps,
} from '@fluentui/react-table';

export type { DataGridBodyProps } from './DataGridBody';
export type { DataGridBodyProps, RowRenderer } from './DataGridBody';
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
PeopleRegular,
DocumentPdfRegular,
VideoRegular,
MoreHorizontalRegular,
} from '@fluentui/react-icons';
import {
TableColumnDefinition,
Expand All @@ -16,6 +17,13 @@ import {
Avatar,
useScrollbarWidth,
useFluent,
TableCellActions,
Menu,
MenuTrigger,
MenuItem,
MenuList,
MenuPopover,
Button,
} from '@fluentui/react-components';
import {
DataGridBody,
Expand All @@ -24,6 +32,7 @@ import {
DataGridHeader,
DataGridCell,
DataGridHeaderCell,
RowRenderer,
} from '@fluentui/react-data-grid-react-window';

type FileCell = {
Expand Down Expand Up @@ -109,6 +118,21 @@ const columns: TableColumnDefinition<Item>[] = [
<TableCellLayout media={item.file.icon}>
<strong>[{item.index}] </strong>
{item.file.label}
<TableCellActions>
<Menu>
<MenuTrigger>
<Button appearance="subtle" aria-label="more" icon={<MoreHorizontalRegular />} />
</MenuTrigger>

<MenuPopover>
<MenuList>
<MenuItem>Item</MenuItem>
<MenuItem>Item</MenuItem>
<MenuItem>Item</MenuItem>
</MenuList>
</MenuPopover>
</Menu>
</TableCellActions>
</TableCellLayout>
);
},
Expand Down Expand Up @@ -154,6 +178,12 @@ const columns: TableColumnDefinition<Item>[] = [
}),
];

const renderRow: RowRenderer<Item> = ({ item, rowId }, style) => (
<DataGridRow<Item> key={rowId} style={style}>
{({ renderCell }) => <DataGridCell>{renderCell(item)}</DataGridCell>}
</DataGridRow>
);

export const Virtualization = () => {
const { targetDocument } = useFluent();
const scrollbarWidth = useScrollbarWidth({ targetDocument });
Expand All @@ -166,11 +196,7 @@ export const Virtualization = () => {
</DataGridRow>
</DataGridHeader>
<DataGridBody<Item> itemSize={50} height={400}>
{({ item, rowId }, style) => (
<DataGridRow<Item> key={rowId} style={style}>
{({ renderCell }) => <DataGridCell>{renderCell(item)}</DataGridCell>}
</DataGridRow>
)}
{renderRow}
</DataGridBody>
</DataGrid>
);
Expand All @@ -186,6 +212,9 @@ Virtualization.parameters = {
'by [react-window](https://react-window.vercel.app/#/examples/list/fixed-size).',
'',
'The example below shows how to use this extension package to virtualize the DataGrid component.',
'',
'> ⚠️ Make sure to memoize the row render function to avoid excessive unmouting/mounting of components.',
'react-window will [create components based on this renderer](https://react-window.vercel.app/#/api/FixedSizeList)',
].join('\n'),
},
},
Expand Down

0 comments on commit 1745a0b

Please sign in to comment.