diff --git a/src/components/timeline/TrackPowerGraph.js b/src/components/timeline/TrackPowerGraph.js index fb37584271..b930e1424c 100644 --- a/src/components/timeline/TrackPowerGraph.js +++ b/src/components/timeline/TrackPowerGraph.js @@ -5,6 +5,7 @@ // @flow import * as React from 'react'; +import { InView } from 'react-intersection-observer'; import { withSize } from 'firefox-profiler/components/shared/WithSize'; import explicitConnect from 'firefox-profiler/utils/connect'; import { bisectionRight } from 'firefox-profiler/utils/bisect'; @@ -57,7 +58,10 @@ type CanvasProps = {| */ class TrackPowerCanvas extends React.PureComponent { _canvas: null | HTMLCanvasElement = null; - _requestedAnimationFrame: boolean = false; + _canvasState: {| renderScheduled: boolean, inView: boolean |} = { + renderScheduled: false, + inView: false, + }; drawCanvas(canvas: HTMLCanvasElement): void { const { @@ -174,16 +178,20 @@ class TrackPowerCanvas extends React.PureComponent { } } - _scheduleDraw() { - if (!this._requestedAnimationFrame) { - this._requestedAnimationFrame = true; - window.requestAnimationFrame(() => { - this._requestedAnimationFrame = false; - const canvas = this._canvas; - if (canvas) { - this.drawCanvas(canvas); - } - }); + _renderCanvas() { + if (!this._canvasState.inView) { + // Canvas is not in the view. Schedule the render for a later intersection + // observer callback. + this._canvasState.renderScheduled = true; + return; + } + + // Canvas is in the view. Render the canvas and reset the schedule state. + this._canvasState.renderScheduled = false; + + const canvas = this._canvas; + if (canvas) { + this.drawCanvas(canvas); } } @@ -191,11 +199,26 @@ class TrackPowerCanvas extends React.PureComponent { this._canvas = canvas; }; + _observerCallback = (inView: boolean, _entry: IntersectionObserverEntry) => { + this._canvasState.inView = inView; + if (!this._canvasState.renderScheduled) { + // Skip if render is not scheduled. + return; + } + + this._renderCanvas(); + }; + render() { - this._scheduleDraw(); + this._renderCanvas(); return ( - + + + ); } } diff --git a/src/selectors/profile.js b/src/selectors/profile.js index 1d6614acd9..62a52b8bce 100644 --- a/src/selectors/profile.js +++ b/src/selectors/profile.js @@ -282,13 +282,14 @@ export const getCounterSelectors = (index: CounterIndex): CounterSelectors => { * type of the function. */ function _createCounterSelectors(counterIndex: CounterIndex) { - const getCounter: Selector = (state) => + const getCounter: Selector = createSelector(getProfile, (profile) => processCounter( ensureExists( - getProfile(state).counters, + profile.counters, 'Attempting to get a counter by index, but no counters exist.' )[counterIndex] - ); + ) + ); const getDescription: Selector = (state) => getCounter(state).description; diff --git a/src/test/components/__snapshots__/TrackPower.test.js.snap b/src/test/components/__snapshots__/TrackPower.test.js.snap index 9c8b7ca90f..ff26e785a8 100644 --- a/src/test/components/__snapshots__/TrackPower.test.js.snap +++ b/src/test/components/__snapshots__/TrackPower.test.js.snap @@ -128,11 +128,13 @@ exports[`TrackPower matches the component snapshot 1`] = `
- +
+ +
diff --git a/src/utils/react.js b/src/utils/react.js new file mode 100644 index 0000000000..54065c8c7e --- /dev/null +++ b/src/utils/react.js @@ -0,0 +1,37 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// @flow + +// This file contains some functions that might be interesting when debugging +// react code. + +// This function keeps track of the props of a React component and logs the +// changes between two calls. This is best used in render() or +// componentDidUpdate() like this: +// import { logPropChanges } from 'firefox-profiler/utils/react'; +// ... +// render() { +// logPropChanges(this); +// } +export function logPropChanges(component: any) { + if (!component.__DEBUG__oldProps) { + component.__DEBUG__oldProps = component.props; + return; + } + + for (const [prop, value] of Object.entries(component.props)) { + const oldValue = component.__DEBUG__oldProps[prop]; + if (oldValue !== value) { + console.log( + `prop "${prop}" changed: old value is`, + oldValue, + ', new value is', + value + ); + } + } + + component.__DEBUG__oldProps = component.props; +}