The Profiler requires an onRender function as a prop. React calls this function any time a component within the profiled tree “commits” an update.
However, given:
import React from 'react'
import ReactDOM from 'react-dom'
function Counter() {
const [count, setCount] = React.useState(0)
const increment = () => setCount(c => c + 1)
return <button onClick={increment}>{count}</button>
}
function App() {
return (
<div>
<React.Profiler
id="counter"
onRender={() => console.log('called')}
>
<div>
Profiled counter
<Counter />
</div>
</React.Profiler>
<div>
Unprofiled counter
<Counter />
</div>
</div>
)
}
ReactDOM.render(<App />, document.getElementById('root'))
I'm getting a log when I click on the unprofiled counter.
Reproduction: https://codesandbox.io/s/react-codesandbox-tnff6
Am I misunderstanding this API, or is this a bug?
As the state is being updated by Counter function which is being called on both the profiled and unprofiled counter, is causing re render and console.log is being called both the times.
Thanks @Priyankasingh12, but I'm pretty sure that the way it's documented (and what would be sensible) it shouldn't be operating like that. Also, I tried making a separate component instead of using the same one and I got the same result.
At a quick glance it does look unexpected. Don't have time to dig in further at the moment though.
It seems that this occurs for elements which have same type with greater or equal depth in same tree.
See: https://codesandbox.io/s/react-codesandbox-1t6cv
I don't think it has anything to do with the element type, but where they are declared relative to where the <Profiler> tags are defined.
It looks like for a subtree that belongs to a single owner- rendering further down in the subtree will cause the Profiler higher up to call onRender.
const Bar = () => (
<>
<Profiler id="A">
<A />
</Profiler>
<div>
<Profiler id="B">
<B />
</Profiler>
</div>
</>
);
const Foo = () => (
<Profiler id="root">
<Bar />
<C />
</Profiler>
);
Given the above example:
| | A | B | root |
|----------|---|---|------|
| update A | ✓ | | ✓ |
| update B | ✓ | ✓ | ✓ |
| update C | | | ✓ |
This does not look to be hooks-specific, nor is it a recent regression. (Same behavior is exhibited for class components in the earliest release of the Profiler component- v16.5.)
It seems that the Profiler fiber is always marked as Update in beginWork phase.
Thanks @bvaughn!
Most helpful comment
It seems that the
Profiler fiberis always marked asUpdateinbeginWorkphase.