Call onSelect when a DataSource item changes

Summary:
Currently, we call onSelect in DataTable only when user changes their selection. At that moment, we pass the row data to the `onSelect` callback. However, if later the data changes, but the selection stays the same, we do not call `onSelect` again. As result, any listener to onSelect does not receive the latest data.
In this diff, we start calling `onSelect` when the selection does not change, but the underlying data does.

Reviewed By: mweststrate

Differential Revision: D37520346

fbshipit-source-id: a88d34654e9ad0721caf5918dde49b86ba20fc1f
This commit is contained in:
Andrey Goncharov
2022-06-30 07:01:54 -07:00
committed by Facebook GitHub Bot
parent 1052384154
commit f8763f95fa
7 changed files with 57 additions and 18 deletions

View File

@@ -472,7 +472,7 @@ class DataSourceView<T, KeyType> {
*/
public windowEnd = 0;
private outputChangeListener?: (change: OutputChange) => void;
private outputChangeListeners = new Set<(change: OutputChange) => void>();
/**
* This is the base view data, that is filtered and sorted, but not reversed or windowed
@@ -520,11 +520,11 @@ class DataSourceView<T, KeyType> {
this.windowEnd = end;
}
public setListener(listener?: (change: OutputChange) => void) {
if (this.outputChangeListener && listener) {
console.warn('outputChangeListener already set');
}
this.outputChangeListener = listener;
public addListener(listener: (change: OutputChange) => void) {
this.outputChangeListeners.add(listener);
return () => {
this.outputChangeListeners.delete(listener);
};
}
public setSortBy(sortBy: undefined | keyof T | ((a: T) => Primitive)) {
@@ -617,23 +617,27 @@ class DataSourceView<T, KeyType> {
};
}
private notifyAllListeners(change: OutputChange) {
this.outputChangeListeners.forEach((listener) => listener(change));
}
private notifyItemUpdated(viewIndex: number) {
viewIndex = this.normalizeIndex(viewIndex);
if (
!this.outputChangeListener ||
!this.outputChangeListeners.size ||
viewIndex < this.windowStart ||
viewIndex >= this.windowEnd
) {
return;
}
this.outputChangeListener({
this.notifyAllListeners({
type: 'update',
index: viewIndex,
});
}
private notifyItemShift(index: number, delta: number) {
if (!this.outputChangeListener) {
if (!this.outputChangeListeners.size) {
return;
}
let viewIndex = this.normalizeIndex(index);
@@ -641,7 +645,7 @@ class DataSourceView<T, KeyType> {
viewIndex -= delta; // we need to correct for normalize already using the new length after applying this change
}
// Idea: we could add an option to automatically shift the window for before events.
this.outputChangeListener({
this.notifyAllListeners({
type: 'shift',
delta,
index: viewIndex,
@@ -656,7 +660,7 @@ class DataSourceView<T, KeyType> {
}
private notifyReset(count: number) {
this.outputChangeListener?.({
this.notifyAllListeners({
type: 'reset',
newCount: count,
});

View File

@@ -66,7 +66,7 @@ export const DataSourceRendererStatic: <T extends object, C>(
let unmounted = false;
dataSource.view.setWindow(0, dataSource.limit);
dataSource.view.setListener((_event) => {
const unsubscribe = dataSource.view.addListener((_event) => {
if (unmounted) {
return;
}
@@ -75,7 +75,7 @@ export const DataSourceRendererStatic: <T extends object, C>(
return () => {
unmounted = true;
dataSource.view.setListener(undefined);
unsubscribe();
};
},
[dataSource, setForceUpdate, useFixedRowHeight],

View File

@@ -170,7 +170,7 @@ export const DataSourceRendererVirtual: <T extends object, C>(
}
}
dataSource.view.setListener((event) => {
const unsubscribe = dataSource.view.addListener((event) => {
switch (event.type) {
case 'reset':
rerender(UpdatePrio.HIGH, true);
@@ -201,7 +201,7 @@ export const DataSourceRendererVirtual: <T extends object, C>(
return () => {
unmounted = true;
dataSource.view.setListener(undefined);
unsubscribe();
};
},
[dataSource, setForceUpdate, useFixedRowHeight, isUnitTest],

View File

@@ -489,9 +489,9 @@ function testEvents<T>(
): any[] {
const ds = createDataSource<T, keyof T>(initial, {key});
const events: any[] = [];
ds.view.setListener((e) => events.push(e));
const unsubscribe = ds.view.addListener((e) => events.push(e));
op(ds);
ds.view.setListener(undefined);
unsubscribe();
return events;
}