37
loading...
This website collects cookies to deliver better user experience
Performance
tab. The profiler can help point out that obvious case where you have a super slow function, or when you are calling a function too many times. Usually it'll show the lowest hanging fruit.slowFunc()
shows the most "Self Time", so it likely does a bunch of additional processing within its function boundary. That is, it's not calling some other slow function, it is slow itself.render()
, has a high "Total Time", but a low "Self Time". It does very little itself, but calls something slow: slowFunc()
.slowFunc()
, you can see that it is called by render()
. If multiple functions are calling slowFunc()
, there will be more than one line here.slowFunc()
example is the following: render()
calls slowFunc()
directly.function slowFunc () {
for (let i = 0; i < 100; i++) {
console.log('Hello', Math.random())
}
}
const SlowComponent = () => {
slowFunc()
return "I'm slow :("
}
const App = () => (
<>
<SlowComponent />
<SlowComponent />
// 100 more SlowComponent renders
</>
)
slowFunc()
here. But what if it is doing necessary work? The real world is often much messier.Performance
tab and clicking Record
, you can programmatically generate performance profiles for later viewing. This is useful if you want to capture a very specific part of the code. For example:console.profile('The slow thing')
doTheSlowThing()
console.profileEnd('The slow thing')
1ms of 100ms
, 1ms
is the self time; the time that was spent rendering this component, and 100ms
is the total time; the time spent rendering itself and all its children.const start = performance.now()
doSlowOperation()
console.log('Time to do slow operation', performance.now() - start)
class MyComponent extends React.Component {
handleStartSlowOperation = () => {
this.startPerf = performance.now()
kickOffSlow()
}
handleSlowOperationDone = () => {
console.log('Time to do slow operation', performance.now() - this.startPerf)
}
render () {
// ...
}
}
Field
component's render function:for (let i = 0; i < 10; i++) {
_.uniq(_.times(10000))
}
lodash
functions at the top of the list:componentDidUpdate
func. In my case, it will look something like:class Editor extends React.Component {
handleKeystroke = (event) => {
this.startTime = performance.now()
this.lastChange = {
label: event.target.value,
index: event.target.index,
}
this.props.onChangeLabel(event)
}
componentDidUpdate = () => {
const lastChange = this.lastChange
if (this.props.fields[lastChange.index].label === lastChange.label) {
console.log('Keystroke millis', performance.now() - this.startTime)
}
}
render () {
// ...
}
}
Field
components, or optimizing the render
method in each Field
component. Intuitively, it feels like the best option is just to render fewer components here, but we won't really know until we try and note the change in performance.Field
component's render
func? We still render all field components, but each does the absolute minimum: only render an empty div
in the Field
render function. How much does that impact the total time?const Field = () => <div />
div
.const Field = () => {
// Is props setup slow?
const fieldInfo = buildFieldInfo()
return (<div />)
}
false
from shouldComponentUpdate
. shouldComponentUpdate
is a React lifecycle function that allows you to control when something re-renders. Returning false
from it will tell React to render the component only once (initially), then never again. This will tell us how much it takes to render the parent on a label change.shouldComponentUpdate
in the next post in this series.class Field extends React.Component {
shouldComponentUpdate (nextProps) {
return false
}
render() {
const fieldInfo = buildFieldInfo()
return (<TheFieldComponents {...fieldInfo} />)
}
}
shouldComponentUpdate
. This check might not be totally correct, but we can simulate what it looks like to only render the changed field. Note that we are doing a full render in the Field
component's render
func, instead of just rendering a div
like in other examples.class Field extends React.Component {
shouldComponentUpdate (nextProps) {
return this.props.field.label !== nextProps.field.label
}
render() {
const fieldInfo = buildFieldInfo()
return (<TheFieldComponents {...fieldInfo} />)
}
}
styled.div
:Field
components in the webform twice. Does it need to?Field
components on changes that do not necessarily affect all fields.Field
component is a bottleneck. This doesn't seem to be a huge problem when only one field changes, but it could be a big deal for changes that do affect all fields, or initial render.Field
component. Then if there was time, I would dig into fixing props-building for each Field
render.