Skip to content

Commit 2af6a8c

Browse files
committed
refactored core
1 parent 7e0fda7 commit 2af6a8c

1 file changed

Lines changed: 110 additions & 53 deletions

File tree

src/extension/components/ReactPerfDevtool.js

Lines changed: 110 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
import React from 'react'
2+
23
import { Metrics } from './Metrics'
3-
import { Results } from './Results'
44
import { ErrorComponent } from './ErrorComponent'
55
import { Measures } from './Measures'
6+
import { Buttons } from './Buttons'
7+
import { Stats } from './Stats'
8+
9+
import { computeTotalTime, getResults } from '../util'
610

711
const theme = require('../theme')
812

@@ -45,16 +49,16 @@ export class ReactPerfDevtool extends React.Component {
4549
pendingEvents: 0, // Pending event count.
4650
rawMeasures: [], // Raw measures output. It is used for rendering the overall results.
4751
loading: false, // To show the loading output while collecting the results.
48-
hasError: false // Track errors, occurred when collecting the measures.
52+
hasError: false, // Track errors, occurred when collecting the measures.
53+
showChart: false
4954
}
5055
}
5156

52-
reloadInspectedWindow = () => chrome.devtools.inspectedWindow.reload()
53-
5457
componentWillMount() {
5558
// When the devtool is launched first, measures may not be available.
5659
// Reload the window again to get the new measures and then display them.
57-
// TODO: Remove this hack (possible architecture change)
60+
// Why ? We rely on the observer hook that the user has installed in his/her project.
61+
// This chrome plugin is just way to interpret the results derived from the observer's API
5862
if (store.length === 0) {
5963
this.reloadInspectedWindow()
6064
}
@@ -66,18 +70,94 @@ export class ReactPerfDevtool extends React.Component {
6670

6771
// Get the total measures and flush them if the store is empty.
6872
this.timer = setInterval(() => this.getMeasuresLength(), 2000)
73+
74+
// Show the chart when we have the measures
75+
this.setState({ showChart: true })
6976
}
7077

7178
componentWillUnmount() {
7279
clearInterval(this.timer)
7380
}
7481

82+
reloadInspectedWindow = () => chrome.devtools.inspectedWindow.reload()
83+
84+
chartOptions = ({
85+
totalTime,
86+
commitChanges,
87+
hostEffects,
88+
lifecycleTime,
89+
totalComponents,
90+
totalEffects,
91+
totalLifecycleMethods
92+
}) => ({
93+
type: 'doughnut',
94+
data: {
95+
datasets: [
96+
{
97+
data: [totalTime, commitChanges, hostEffects, lifecycleTime],
98+
backgroundColor: ['#ff9999', '#99ffdd', '#d98cb3', '#ffff4d']
99+
}
100+
],
101+
102+
// These labels appear in the legend and in the tooltips when hovering different arcs
103+
labels: [
104+
`${totalComponents} components (ms)`,
105+
'Committing changes (ms)',
106+
`Committing ${totalEffects} host ${
107+
totalEffects === 1 || totalEffects === 0 ? 'effect' : 'effects'
108+
} (ms)`,
109+
`Calling ${totalLifecycleMethods} ${
110+
totalLifecycleMethods === 1 || totalLifecycleMethods === 0
111+
? 'lifecycle hook'
112+
: 'lifecycle hooks'
113+
} (ms)`
114+
]
115+
},
116+
options: {
117+
responsive: false,
118+
maintainAspectRatio: false
119+
}
120+
})
121+
122+
getChartData = props => {
123+
const totalEffects = getResults(props.rawMeasures).totalEffects
124+
const hostEffects = getResults(props.rawMeasures).hostEffectsTime
125+
const commitChanges = getResults(props.rawMeasures).commitChangesTime
126+
const totalLifecycleMethods = getResults(props.rawMeasures)
127+
.totalLifecycleMethods
128+
const lifecycleTime = getResults(props.rawMeasures).lifecycleTime
129+
const totalTime = computeTotalTime(
130+
props.rawMeasures,
131+
props.totalTime
132+
).toFixed(2)
133+
134+
return {
135+
totalEffects,
136+
hostEffects,
137+
commitChanges,
138+
totalLifecycleMethods,
139+
lifecycleTime,
140+
totalTime,
141+
totalComponents: props.totalComponents
142+
}
143+
}
144+
145+
drawChart = props => {
146+
const contex = document.getElementById('myChart')
147+
const Chart = this.props.Graphics
148+
149+
const statsChart = new Chart(
150+
contex,
151+
this.chartOptions(this.getChartData(props))
152+
)
153+
}
154+
155+
setErrorState = () => this.setState({ hasError: true, loading: false })
156+
75157
getMeasuresLength = () => {
76158
this.evaluate(queries['measuresLength'], (count, err) => {
77-
// TODO: Inspect this behaviour (possibly a bug)
78-
// We need to check the measures count also because it may happen that a user reloads the page and see no results.
79-
if (err && count === 0) {
80-
this.setState({ hasError: true })
159+
if (err || count === 0) {
160+
this.setErrorState()
81161
return
82162
}
83163

@@ -104,26 +184,27 @@ export class ReactPerfDevtool extends React.Component {
104184
}
105185

106186
getMeasures = () => {
107-
// Returns the performance entries which are not parsed and not aggregated (required for generating the overall result)
187+
// Returns the performance entries which are not parsed and not aggregated
188+
// These measures are required for creating the chart.
108189
this.getRawMeasures()
109190

110191
this.evaluate(queries['measures'], (measures, err) => {
111192
if (err) {
112-
this.setState({ hasError: true })
193+
this.setErrorState()
113194
return
114195
}
115196

116-
// Update the state.
117197
this.updateMeasures(JSON.parse(measures))
118198
})
119199
}
120200

121201
getRawMeasures = () => {
122202
this.evaluate(queries['rawMeasures'], (measures, err) => {
123203
if (err) {
124-
this.setState({ hasError: true })
204+
this.setErrorState()
125205
return
126206
}
207+
127208
this.setState({
128209
rawMeasures: JSON.parse(measures)
129210
})
@@ -133,17 +214,25 @@ export class ReactPerfDevtool extends React.Component {
133214
updateMeasures = measures => {
134215
store = store.concat(measures)
135216

217+
this.drawChart({
218+
totalTime: store
219+
.reduce((acc, comp) => acc + comp.totalTimeSpent, 0)
220+
.toFixed(2),
221+
rawMeasures: this.state.rawMeasures,
222+
totalComponents: store.length
223+
})
224+
136225
this.setState({
137226
perfData: store,
138227
totalTime: store
139228
.reduce((acc, comp) => acc + comp.totalTimeSpent, 0)
140229
.toFixed(2)
141230
})
142231

232+
// Clear the shared state, so that new measures can be appended (and they don't override)
143233
this.clearMeasures()
144234
}
145235

146-
// TODO: This is not an accurate way to clear the shared state (store on the window object).
147236
clearMeasures = () => this.evaluate(queries['clear'])
148237

149238
// Clear the panel content.
@@ -154,7 +243,8 @@ export class ReactPerfDevtool extends React.Component {
154243
perfData: store,
155244
totalTime: 0,
156245
rawMeasures: [],
157-
pendingEvents: 0
246+
pendingEvents: 0,
247+
showChart: false
158248
})
159249

160250
this.clearMeasures()
@@ -174,26 +264,6 @@ export class ReactPerfDevtool extends React.Component {
174264
this.reloadInspectedWindow()
175265
}
176266

177-
showDocLink = () => {
178-
if (this.state.perfData.length > 0) {
179-
return (
180-
<a
181-
className="doc-link"
182-
style={{
183-
textDecoration: 'none',
184-
paddingBottom: '10px',
185-
color: theme === 'dark' ? 'blue' : null
186-
}}
187-
target="_blank"
188-
href="https://github.com/nitin42/react-perf-devtool"
189-
>
190-
👉 &nbsp;Check the documentation to learn more about how these stats
191-
are calculated and different phases.
192-
</a>
193-
)
194-
}
195-
}
196-
197267
render() {
198268
if (this.state.loading) {
199269
return (
@@ -204,7 +274,7 @@ export class ReactPerfDevtool extends React.Component {
204274
<p
205275
className={theme === 'dark' ? 'dark-loading-text' : 'loading-text'}
206276
>
207-
Connecting to React Performance Devtool...
277+
Collecting React performance measures...
208278
</p>
209279
</div>
210280
)
@@ -213,34 +283,21 @@ export class ReactPerfDevtool extends React.Component {
213283
return (
214284
<div style={this.panelStyles}>
215285
<div style={{ display: 'inlineBlock' }}>
216-
<button
217-
className={theme === 'dark' ? 'dark-btn' : 'btn'}
218-
onClick={this.clear}
219-
>
220-
Clear
221-
</button>
222-
<button
223-
className={theme === 'dark' ? 'dark-btn' : 'btn'}
224-
onClick={this.reload}
225-
>
226-
Reload
227-
</button>
286+
<Buttons theme={theme} clear={this.clear} reload={this.reload} />
228287
<span style={{ fontWeight: 'bold', padding: '8px' }}>
229-
Pending Events: {this.state.pendingEvents}
288+
Pending events: {this.state.pendingEvents}
230289
</span>
231290
</div>
232291
{this.state.hasError ? (
233292
<ErrorComponent />
234293
) : (
235294
<React.Fragment>
236295
<Metrics measures={this.state.perfData} />
237-
<Results
238-
rawMeasures={this.state.rawMeasures}
296+
<Stats
297+
showChart={this.state.showChart}
239298
totalTime={this.state.totalTime}
240-
loading={this.state.loading}
241299
/>
242300
<Measures measures={this.state.perfData} />
243-
{this.showDocLink()}
244301
</React.Fragment>
245302
)}
246303
</div>

0 commit comments

Comments
 (0)