Skip to content

Commit 7bee51d

Browse files
obreitwiLFDanLu
andauthored
fix: TableView jump to top on asynchronous load (#8133)
* fix: TableView jump to top on asynchronous load * add test story --------- Co-authored-by: Daniel Lu <[email protected]>
1 parent 2d9db12 commit 7bee51d

File tree

2 files changed

+75
-10
lines changed

2 files changed

+75
-10
lines changed

packages/@react-spectrum/table/stories/Table.stories.tsx

Lines changed: 69 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1485,14 +1485,13 @@ export const AsyncLoadingClientFiltering: TableStory = {
14851485
name: 'async client side filter loading'
14861486
};
14871487

1488+
interface StarWarsItem {
1489+
name: string,
1490+
height: string,
1491+
mass: string
1492+
}
14881493

14891494
function AsyncServerFilterTable(props) {
1490-
interface Item {
1491-
name: string,
1492-
height: string,
1493-
mass: string
1494-
}
1495-
14961495
let columns = [
14971496
{
14981497
name: 'Name',
@@ -1509,7 +1508,7 @@ function AsyncServerFilterTable(props) {
15091508
}
15101509
];
15111510

1512-
let list = useAsyncList<Item>({
1511+
let list = useAsyncList<StarWarsItem>({
15131512
getKey: (item) => item.name,
15141513
async load({signal, cursor, filterText}) {
15151514
if (cursor) {
@@ -2197,4 +2196,67 @@ function LoadingTable() {
21972196
);
21982197
}
21992198

2199+
function AsyncLoadOverflowWrapRepro() {
2200+
let columns = [
2201+
{name: 'Name', key: 'name'},
2202+
{name: 'Height', key: 'height'},
2203+
{name: 'Mass', key: 'mass'},
2204+
{name: 'Birth Year', key: 'birth_year'}
2205+
];
2206+
2207+
let list = useAsyncList<StarWarsItem>({
2208+
async load({signal, cursor}) {
2209+
if (cursor) {
2210+
cursor = cursor.replace(/^http:\/\//i, 'https://');
2211+
}
2212+
2213+
let res = await fetch(
2214+
cursor || 'https://swapi.py4e.com/api/people/?search=',
2215+
{signal}
2216+
);
2217+
let json = await res.json();
2218+
2219+
return {
2220+
items: json.results,
2221+
cursor: json.next
2222+
};
2223+
}
2224+
});
2225+
2226+
return (
2227+
<TableView
2228+
aria-label="example async loading table"
2229+
height="size-3000"
2230+
overflowMode="wrap">
2231+
<TableHeader columns={columns}>
2232+
{(column) => (
2233+
<Column align={column.key !== 'name' ? 'end' : 'start'}>
2234+
{column.name}
2235+
</Column>
2236+
)}
2237+
</TableHeader>
2238+
<TableBody
2239+
items={list.items}
2240+
loadingState={list.loadingState}
2241+
onLoadMore={list.loadMore}>
2242+
{(item) => (
2243+
<Row key={item.name}>
2244+
{(key) => (
2245+
<Cell>{`${item[key]}++++${item[key]}++++${item[key]}++++`}</Cell>
2246+
)}
2247+
</Row>
2248+
)}
2249+
</TableBody>
2250+
</TableView>
2251+
);
2252+
}
2253+
2254+
export const AsyncLoadOverflowWrapReproStory: TableStory = {
2255+
render: (args) => <AsyncLoadOverflowWrapRepro {...args} />,
2256+
name: 'async, overflow wrap scroll jumping reproduction',
2257+
parameters: {description: {data: `
2258+
Rapidly scrolling down through this table should not cause the scroll position to jump to the top.
2259+
`}}
2260+
};
2261+
22002262
export {Performance} from './Performance';

packages/@react-stately/layout/src/TableLayout.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,12 @@ export class TableLayout<T, O extends TableLayoutProps = TableLayoutProps> exten
6868
// If columnWidths were provided via layoutOptions, update those.
6969
// Otherwise, calculate column widths ourselves.
7070
if (invalidationContext.layoutOptions?.columnWidths) {
71-
if (invalidationContext.layoutOptions.columnWidths !== this.columnWidths) {
72-
this.columnWidths = invalidationContext.layoutOptions.columnWidths;
73-
invalidationContext.sizeChanged = true;
71+
for (const [key, val] of invalidationContext.layoutOptions.columnWidths) {
72+
if (this.columnWidths.get(key) !== val) {
73+
this.columnWidths = invalidationContext.layoutOptions.columnWidths;
74+
invalidationContext.sizeChanged = true;
75+
break;
76+
}
7477
}
7578
} else if (invalidationContext.sizeChanged || this.columnsChanged(newCollection, this.lastCollection)) {
7679
let columnLayout = new TableColumnLayout({});

0 commit comments

Comments
 (0)