import * as React from 'react' import * as q from '../../../../backend/src/Model' import { makeConnectionMessageEvent, rendererEvents, MqttMessage } from '../../../../events' import { AppState } from '../../reducers' import TreeNode from './TreeNode' import { connect } from 'react-redux' const MovingAverage = require('moving-average') const timeInterval = 10 * 1000 const average = MovingAverage(timeInterval) declare var window: any interface Props { autoExpandLimit: number didSelectNode?: (node: q.TreeNode) => void connectionId?: string tree?: q.Tree } class Tree extends React.Component { private updateTimer?: any private lastUpdate: number = 0 private perf: number = 0 constructor(props: any) { super(props) this.state = { } } public time(): number { const time = performance.now() - this.perf this.perf = performance.now() return time } public componentWillReceiveProps(nextProps: Props) { if (this.props.tree !== nextProps.tree) { if (this.props.tree) { this.props.tree.onMerge.unsubscribe(this.throttledTreeUpdate) } if (nextProps.tree) { nextProps.tree.onMerge.subscribe(this.throttledTreeUpdate) } } } public throttledTreeUpdate = () => { if (this.updateTimer) { return } const expectedRenderTime = average.forecast() const updateInterval = Math.max(expectedRenderTime * 7, 300) const timeUntilNextUpdate = updateInterval - (performance.now() - this.lastUpdate) this.updateTimer = setTimeout(() => { window.requestIdleCallback(() => { this.lastUpdate = performance.now() this.updateTimer && clearTimeout(this.updateTimer) this.updateTimer = undefined this.setState(this.state) }, { timeout: 500 }) }, Math.max(0, timeUntilNextUpdate)) } public componentWillUnmount() { if (this.props.connectionId) { const event = makeConnectionMessageEvent(this.props.connectionId) rendererEvents.unsubscribeAll(event) } } public render() { if (!this.props.tree) { return null } const style: React.CSSProperties = { lineHeight: '1.1', cursor: 'default', } return (
) } private performanceCallback = (ms: number) => { average.push(Date.now(), ms) } } const mapStateToProps = (state: AppState) => { return { autoExpandLimit: state.settings.autoExpandLimit, tree: state.connection.tree, } } export default connect(mapStateToProps)(Tree)