mirror of
https://github.com/pezkuwichain/pezkuwi-telemetry.git
synced 2026-06-15 01:21:03 +00:00
Don't sort the list on every render (#58)
This commit is contained in:
@@ -3,7 +3,7 @@ import { Types } from '@dotstats/common';
|
||||
import { Chains, Chain, Ago, OfflineIndicator } from './components';
|
||||
import { Connection } from './Connection';
|
||||
import { PersistentObject, PersistentSet } from './persist';
|
||||
import { State } from './state';
|
||||
import { State, compareNodes } from './state';
|
||||
|
||||
import './App.css';
|
||||
|
||||
@@ -36,13 +36,13 @@ export default class App extends React.Component<{}, State> {
|
||||
);
|
||||
|
||||
this.pins = new PersistentSet<Types.NodeName>('pinned_names', (pins) => {
|
||||
const { nodes } = this.state;
|
||||
const { nodes, sortedNodes } = this.state;
|
||||
|
||||
for (const node of nodes.values()) {
|
||||
node.pinned = pins.has(node.nodeDetails[0]);
|
||||
}
|
||||
|
||||
this.setState({ nodes, pins });
|
||||
this.setState({ nodes, pins, sortedNodes: sortedNodes.sort(compareNodes) });
|
||||
});
|
||||
|
||||
this.state = {
|
||||
@@ -54,6 +54,7 @@ export default class App extends React.Component<{}, State> {
|
||||
subscribed: null,
|
||||
chains: new Map(),
|
||||
nodes: new Map(),
|
||||
sortedNodes: [],
|
||||
settings: this.settings.raw(),
|
||||
pins: this.pins.get(),
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { VERSION, timestamp, FeedMessage, Types, Maybe, sleep } from '@dotstats/common';
|
||||
import { State, Update } from './state';
|
||||
import { sortedInsert, sortedIndexOf } from '@dotstats/common';
|
||||
import { State, Update, compareNodes } from './state';
|
||||
import { PersistentSet } from './persist';
|
||||
|
||||
const { Actions } = FeedMessage;
|
||||
@@ -140,9 +141,8 @@ export class Connection {
|
||||
|
||||
private handleMessages = (event: MessageEvent) => {
|
||||
const data = event.data as FeedMessage.Data;
|
||||
const nodes = this.state.nodes;
|
||||
const chains = this.state.chains;
|
||||
const changes = { nodes, chains };
|
||||
const { nodes, chains } = this.state;
|
||||
let { sortedNodes } = this.state;
|
||||
|
||||
messages: for (const message of FeedMessage.deserialize(data)) {
|
||||
switch (message.action) {
|
||||
@@ -176,14 +176,32 @@ export class Connection {
|
||||
const node = { pinned, id, nodeDetails, nodeStats, blockDetails, location };
|
||||
|
||||
nodes.set(id, node);
|
||||
sortedInsert(node, sortedNodes, compareNodes);
|
||||
|
||||
if (nodes.size !== sortedNodes.length) {
|
||||
console.error('Node count in sorted array is wrong!');
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Actions.RemovedNode: {
|
||||
nodes.delete(message.payload);
|
||||
const id = message.payload;
|
||||
const node = nodes.get(id);
|
||||
|
||||
break;
|
||||
if (node) {
|
||||
nodes.delete(id);
|
||||
const index = sortedIndexOf(node, sortedNodes, compareNodes);
|
||||
sortedNodes.splice(index, 1);
|
||||
|
||||
if (nodes.size !== sortedNodes.length) {
|
||||
console.error('Node count in sorted array is wrong!');
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
continue messages;
|
||||
}
|
||||
|
||||
case Actions.LocatedNode: {
|
||||
@@ -191,7 +209,7 @@ export class Connection {
|
||||
const node = nodes.get(id);
|
||||
|
||||
if (!node) {
|
||||
return;
|
||||
continue messages;
|
||||
}
|
||||
|
||||
node.location = [latitude, longitude, city];
|
||||
@@ -204,10 +222,11 @@ export class Connection {
|
||||
const node = nodes.get(id);
|
||||
|
||||
if (!node) {
|
||||
return;
|
||||
continue messages;
|
||||
}
|
||||
|
||||
node.blockDetails = blockDetails;
|
||||
sortedNodes = sortedNodes.sort(compareNodes);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -245,6 +264,7 @@ export class Connection {
|
||||
|
||||
if (this.state.subscribed === message.payload) {
|
||||
nodes.clear();
|
||||
sortedNodes = [];
|
||||
|
||||
this.state = this.update({ subscribed: null, nodes, chains });
|
||||
|
||||
@@ -263,6 +283,7 @@ export class Connection {
|
||||
case Actions.UnsubscribedFrom: {
|
||||
if (this.state.subscribed === message.payload) {
|
||||
nodes.clear();
|
||||
sortedNodes = [];
|
||||
this.state = this.update({ subscribed: null, nodes });
|
||||
}
|
||||
|
||||
@@ -281,7 +302,7 @@ export class Connection {
|
||||
}
|
||||
}
|
||||
|
||||
this.state = this.update(changes);
|
||||
this.state = this.update({ nodes, chains, sortedNodes });
|
||||
|
||||
this.autoSubscribe();
|
||||
}
|
||||
|
||||
@@ -8,34 +8,14 @@
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
||||
.Chain-tabs {
|
||||
position: absolute;
|
||||
right: 9px;
|
||||
bottom: 0;
|
||||
height: 36px;
|
||||
right: 5px;
|
||||
bottom: 10px;
|
||||
width: 200px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.Chain-tab-unit {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.Chain-tab-unit .Icon {
|
||||
margin-right: 1px;
|
||||
font-size: 24px;
|
||||
padding: 6px;
|
||||
background: #ccc;
|
||||
color: #555;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.Chain-tab-unit-on .Icon {
|
||||
background: #222;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.Chain-content-container {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
|
||||
@@ -43,23 +43,6 @@ export namespace Chain {
|
||||
}
|
||||
}
|
||||
|
||||
function sortNodes(a: AppState.Node, b: AppState.Node): number {
|
||||
if (a.pinned === b.pinned) {
|
||||
if (a.blockDetails[0] === b.blockDetails[0]) {
|
||||
const aPropagation = a.blockDetails[4] == null ? Infinity : a.blockDetails[4] as number;
|
||||
const bPropagation = b.blockDetails[4] == null ? Infinity : b.blockDetails[4] as number;
|
||||
|
||||
// Ascending sort by propagation time
|
||||
return aPropagation - bPropagation;
|
||||
}
|
||||
} else {
|
||||
return Number(b.pinned) - Number(a.pinned);
|
||||
}
|
||||
|
||||
// Descending sort by block number
|
||||
return b.blockDetails[0] - a.blockDetails[0];
|
||||
}
|
||||
|
||||
export class Chain extends React.Component<Chain.Props, Chain.State> {
|
||||
constructor(props: Chain.Props) {
|
||||
super(props);
|
||||
@@ -157,9 +140,7 @@ export class Chain extends React.Component<Chain.Props, Chain.State> {
|
||||
<Node.Row.Header settings={settings} />
|
||||
<tbody>
|
||||
{
|
||||
nodes
|
||||
.sort(sortNodes)
|
||||
.map((node) => <Node.Row key={node.id} node={node} settings={settings} pins={pins} />)
|
||||
nodes.map((node) => <Node.Row key={node.id} node={node} settings={settings} pins={pins} />)
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -220,7 +201,7 @@ export class Chain extends React.Component<Chain.Props, Chain.State> {
|
||||
}
|
||||
|
||||
private nodes(): AppState.Node[] {
|
||||
return Array.from(this.props.appState.nodes.values());
|
||||
return this.props.appState.sortedNodes;
|
||||
}
|
||||
|
||||
private pixelPosition(lat: Types.Latitude, lon: Types.Longitude): Node.Location.Position {
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
.Chain-Tab {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.Chain-Tab .Icon {
|
||||
margin-right: 5px;
|
||||
font-size: 24px;
|
||||
padding: 6px;
|
||||
color: #555;
|
||||
cursor: pointer;
|
||||
padding: 10px;
|
||||
border-radius: 40px;
|
||||
transition: background-color 0.15s linear;
|
||||
}
|
||||
|
||||
.Chain-Tab:hover .Icon {
|
||||
background: #ccc;
|
||||
}
|
||||
|
||||
.Chain-Tab-on .Icon, .Chain-Tab-on:hover .Icon {
|
||||
background: #d64ca8;
|
||||
color: #fff;
|
||||
}
|
||||
@@ -2,6 +2,8 @@ import * as React from 'react';
|
||||
import { Chain } from './';
|
||||
import { Icon } from '../';
|
||||
|
||||
import './Tab.css';
|
||||
|
||||
export namespace Tab {
|
||||
export interface Props {
|
||||
label: string;
|
||||
@@ -17,7 +19,7 @@ export class Tab extends React.Component<Tab.Props, {}> {
|
||||
public render() {
|
||||
const { label, icon, display, current } = this.props;
|
||||
const highlight = display === current;
|
||||
const className = highlight ? 'Chain-tab-unit-on Chain-tab-unit' : 'Chain-tab-unit';
|
||||
const className = highlight ? 'Chain-Tab-on Chain-Tab' : 'Chain-Tab';
|
||||
|
||||
return (
|
||||
<div className={className} onClick={this.onClick}>
|
||||
|
||||
@@ -35,8 +35,26 @@ export interface State {
|
||||
subscribed: Maybe<Types.ChainLabel>;
|
||||
chains: Map<Types.ChainLabel, Types.NodeCount>;
|
||||
nodes: Map<Types.NodeId, State.Node>;
|
||||
sortedNodes: State.Node[];
|
||||
settings: Readonly<State.Settings>;
|
||||
pins: Readonly<Set<Types.NodeName>>;
|
||||
}
|
||||
|
||||
export type Update = <K extends keyof State>(changes: Pick<State, K> | null) => Readonly<State>;
|
||||
|
||||
export function compareNodes(a: State.Node, b: State.Node): number {
|
||||
if (a.pinned === b.pinned) {
|
||||
if (a.blockDetails[0] === b.blockDetails[0]) {
|
||||
const aPropagation = a.blockDetails[4] == null ? Infinity : a.blockDetails[4] as number;
|
||||
const bPropagation = b.blockDetails[4] == null ? Infinity : b.blockDetails[4] as number;
|
||||
|
||||
// Ascending sort by propagation time
|
||||
return aPropagation - bPropagation;
|
||||
}
|
||||
} else {
|
||||
return +b.pinned - +a.pinned;
|
||||
}
|
||||
|
||||
// Descending sort by block number
|
||||
return b.blockDetails[0] - a.blockDetails[0];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user