mirror of
https://github.com/pezkuwichain/pezkuwi-telemetry.git
synced 2026-04-22 20:48:05 +00:00
Prevent nodes out of viewport triggering render (#296)
* Prevent nodes out of viewport triggering render * Update frontend/src/common/SortedCollection.ts Co-authored-by: David <dvdplm@gmail.com> * Tweak the comment on `setFocus`, move it closer to `ref` and `hasChangedSince` * Switch `SortedCollection.ref()` to a getter Co-authored-by: David <dvdplm@gmail.com>
This commit is contained in:
@@ -149,7 +149,7 @@ export class Connection {
|
|||||||
|
|
||||||
public handleMessages = (messages: FeedMessage.Message[]) => {
|
public handleMessages = (messages: FeedMessage.Message[]) => {
|
||||||
const { nodes, chains, sortBy, selectedColumns } = this.state;
|
const { nodes, chains, sortBy, selectedColumns } = this.state;
|
||||||
const ref = nodes.ref();
|
const { ref } = nodes;
|
||||||
|
|
||||||
const updateState: UpdateBound = (state) => {
|
const updateState: UpdateBound = (state) => {
|
||||||
this.state = this.update(state);
|
this.state = this.update(state);
|
||||||
|
|||||||
@@ -97,11 +97,27 @@ export namespace SortedCollection {
|
|||||||
export type StateRef = Opaque<number, 'SortedCollection.StateRef'>;
|
export type StateRef = Opaque<number, 'SortedCollection.StateRef'>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Focus {
|
||||||
|
start: number;
|
||||||
|
end: number;
|
||||||
|
}
|
||||||
|
|
||||||
export class SortedCollection<Item extends { id: number }> {
|
export class SortedCollection<Item extends { id: number }> {
|
||||||
|
// Comparator function used to sort the collection
|
||||||
private compare: Compare<Item>;
|
private compare: Compare<Item>;
|
||||||
|
// Mapping item `id` to the `Item`, this uses array as a structure with
|
||||||
|
// the assumption that `id`s provided are increments from `0`, and that
|
||||||
|
// vacant `id`s will be re-used in the future.
|
||||||
private map = Array<Maybe<Item>>();
|
private map = Array<Maybe<Item>>();
|
||||||
|
// Actual sorted list of `Item`s.
|
||||||
private list = Array<Item>();
|
private list = Array<Item>();
|
||||||
|
// Internal tracker for changes, this number increments whenever the
|
||||||
|
// order of the **focused** elements in the collection changes
|
||||||
private changeRef = 0;
|
private changeRef = 0;
|
||||||
|
// Marks the range of indicies that are focused for tracking.
|
||||||
|
// **Note:** `start` is inclusive, while `end` is exclusive (much like
|
||||||
|
// `Array.slice()`).
|
||||||
|
private focus: Focus = { start: 0, end: 0 };
|
||||||
|
|
||||||
constructor(compare: Compare<Item>) {
|
constructor(compare: Compare<Item>) {
|
||||||
this.compare = compare;
|
this.compare = compare;
|
||||||
@@ -114,10 +130,6 @@ export class SortedCollection<Item extends { id: number }> {
|
|||||||
this.changeRef += 1;
|
this.changeRef += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ref(): SortedCollection.StateRef {
|
|
||||||
return this.changeRef as SortedCollection.StateRef;
|
|
||||||
}
|
|
||||||
|
|
||||||
public add(item: Item) {
|
public add(item: Item) {
|
||||||
if (this.map.length <= item.id) {
|
if (this.map.length <= item.id) {
|
||||||
// Grow map if item.id would be out of scope
|
// Grow map if item.id would be out of scope
|
||||||
@@ -131,10 +143,12 @@ export class SortedCollection<Item extends { id: number }> {
|
|||||||
|
|
||||||
this.map[item.id] = item;
|
this.map[item.id] = item;
|
||||||
|
|
||||||
sortedInsert(item, this.list, this.compare);
|
const index = sortedInsert(item, this.list, this.compare);
|
||||||
|
|
||||||
|
if (index < this.focus.end) {
|
||||||
this.changeRef += 1;
|
this.changeRef += 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public remove(id: number) {
|
public remove(id: number) {
|
||||||
const item = this.map[id];
|
const item = this.map[id];
|
||||||
@@ -147,8 +161,10 @@ export class SortedCollection<Item extends { id: number }> {
|
|||||||
this.list.splice(index, 1);
|
this.list.splice(index, 1);
|
||||||
this.map[id] = null;
|
this.map[id] = null;
|
||||||
|
|
||||||
|
if (index < this.focus.end) {
|
||||||
this.changeRef += 1;
|
this.changeRef += 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public get(id: number): Maybe<Item> {
|
public get(id: number): Maybe<Item> {
|
||||||
return this.map[id];
|
return this.map[id];
|
||||||
@@ -184,9 +200,15 @@ export class SortedCollection<Item extends { id: number }> {
|
|||||||
const newIndex = sortedInsert(item, this.list, this.compare);
|
const newIndex = sortedInsert(item, this.list, this.compare);
|
||||||
|
|
||||||
if (newIndex !== index) {
|
if (newIndex !== index) {
|
||||||
|
const outOfFocus =
|
||||||
|
(index < this.focus.start && newIndex < this.focus.start) ||
|
||||||
|
(index >= this.focus.end && newIndex >= this.focus.end);
|
||||||
|
|
||||||
|
if (!outOfFocus) {
|
||||||
this.changeRef += 1;
|
this.changeRef += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public mutAndMaybeSort(
|
public mutAndMaybeSort(
|
||||||
id: number,
|
id: number,
|
||||||
@@ -207,6 +229,7 @@ export class SortedCollection<Item extends { id: number }> {
|
|||||||
public mutEachAndSort(mutator: (item: Item) => void) {
|
public mutEachAndSort(mutator: (item: Item) => void) {
|
||||||
this.list.forEach(mutator);
|
this.list.forEach(mutator);
|
||||||
this.list.sort(this.compare);
|
this.list.sort(this.compare);
|
||||||
|
this.changeRef += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public clear() {
|
public clear() {
|
||||||
@@ -216,6 +239,18 @@ export class SortedCollection<Item extends { id: number }> {
|
|||||||
this.changeRef += 1;
|
this.changeRef += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set a new `Focus`. Any changes to the order of items within the `Focus`
|
||||||
|
// will increment `changeRef`.
|
||||||
|
public setFocus(start: number, end: number) {
|
||||||
|
this.focus = { start, end };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the reference to current ordering state of focused items.
|
||||||
|
public get ref(): SortedCollection.StateRef {
|
||||||
|
return this.changeRef as SortedCollection.StateRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if order of focused items has changed since obtaining a `ref`.
|
||||||
public hasChangedSince(ref: SortedCollection.StateRef): boolean {
|
public hasChangedSince(ref: SortedCollection.StateRef): boolean {
|
||||||
return this.changeRef > ref;
|
return this.changeRef > ref;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,11 +52,11 @@ export class List extends React.Component<List.Props, {}> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const { selectedColumns } = this.props.appState;
|
const { pins, sortBy, appState } = this.props;
|
||||||
const { pins, sortBy } = this.props;
|
const { selectedColumns } = appState;
|
||||||
const { filter } = this.state;
|
const { filter, listStart, listEnd } = this.state;
|
||||||
|
|
||||||
let nodes = this.props.appState.nodes.sorted();
|
let nodes = appState.nodes.sorted();
|
||||||
|
|
||||||
if (filter != null) {
|
if (filter != null) {
|
||||||
nodes = nodes.filter(filter);
|
nodes = nodes.filter(filter);
|
||||||
@@ -73,10 +73,13 @@ export class List extends React.Component<List.Props, {}> {
|
|||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// With filter present, we can no longer guarantee that focus corresponds
|
||||||
|
// to rendering view, so we put the whole list in focus
|
||||||
|
appState.nodes.setFocus(0, nodes.length);
|
||||||
|
} else {
|
||||||
|
appState.nodes.setFocus(listStart, listEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { listStart, listEnd } = this.state;
|
|
||||||
|
|
||||||
const height = TH_HEIGHT + nodes.length * TR_HEIGHT;
|
const height = TH_HEIGHT + nodes.length * TR_HEIGHT;
|
||||||
const transform = `translateY(${listStart * TR_HEIGHT}px)`;
|
const transform = `translateY(${listStart * TR_HEIGHT}px)`;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user