From 317e02a1a3adc69ba0239878873c5d94f9f8b540 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Tue, 22 May 2018 14:31:12 -0700 Subject: [PATCH 01/12] Profiler RFC --- text/0000-profiler.md | 129 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 text/0000-profiler.md diff --git a/text/0000-profiler.md b/text/0000-profiler.md new file mode 100644 index 00000000..152691f5 --- /dev/null +++ b/text/0000-profiler.md @@ -0,0 +1,129 @@ +- Start Date: 2018-05-22 +- RFC PR: (leave this empty) +- React Issue: (leave this empty) + +# Summary + +New React profiling component that collects timing information in order to measure the "cost" of rendering. + +(Note that an experimental release of this component is currently slated for 16.4 as `React.unstable_Profiler`.) + +# Basic example + +`Profiler` can be declared anywhere within a React tree to measure the cost of rendering that portion of the tree. + +For example, to profile a `Navigation` component and its descendants: +```js +render( + + + + +
+ +); +``` + +Multiple `Profiler` components can be used to measure different parts of an application: +```js +render( + + + + + +
+ + +); +``` + +`Profiler` components can also be nested to measure different components within the same subtree: +```js +render( + + + + + + + + + + + + +); +``` + +Although `Profiler` is a light-weight component, it should be used only when necessary; each use adds CPU and memory overhead to an application. + +# Motivation + +It is important that render timing metrics work properly with React's experimental async rendering mode. When asynchronously rendering, React may yield periodically so that an app remains responsive even on low-powered devices. This yielded time (when React is not running) should not be included when considering the "cost" of a render. This distinction is not possible to implement this in user space. + +Timing measurements should also be significantly lighter weight than the current User Timing API so that they can be gathered in production without negatively impacting user experience. (The User Timing API is currently disabled for production because it is slow.) In addition to a faster implementation, we can further limit the impact on existing apps by creating a new production + profiling bundle. This way, apps that don't make use of the `Profiler` component (or wish to disable it globally) will not incur any additional overhead. + +# Detailed design + +The `onRender` callback is called each time a component within the `Profiler` renders. It receives the following parameters: +```js +function onRenderCallback( + id, + phase, + actualTime, + baseTime, + startTime, + commitTime +) { + // Aggregate or log render timings +} + +``` + +#### `id: string` +The `id` value of the `Profiler` tag that was measured. This value can change between renders if e.g. it is derived from `state` or `props`. + +#### `phase: "mount" | "update"` +Either the string "mount" or "update" (depending on whether this root was newly mounted or has just been updated). + +#### `actualTime: number` +Time spent rendering the `Profiler` and its descendants for the current (most recent recent) update. This time tells us how well the subtree makes use of `shouldComponentUpdate` for memoization. Ideally, this time should decrease significantly after the initial mount. + +#### `baseTime: number` +Duration of the most recent `render` time for each individual component within the `Profiler` tree. This reflects a worst-case cost of rendering (e.g. the initial mount or no `shouldComponentUpdate` memoization). + +#### `startTime: number` +Start time identifies when a particular commit started rendering. Although insufficient to determine the cause of the render, it can at least be used to rule out certain interactions (e.g. mouse click, Flux action). This may be helpful if you are also collecting other types of interactions and trying to correlate them with renders. + +Start time isn't just the commit time less the "actual" time, because in async rendering mode React may yield during a render. This "yielded time" (when React was not doing work) is not included in either the "actual" or "base" time measurements. + +#### `commitTime: number` +Commit time could be roughly determined using e.g. `performance.now()` within the `onRender` callback, but multiple `Profiler` components would end up with slightly different times for a single commit. Instead, an explicit time is provided (shared between all `Profiler`s in the commit) enabling them to be grouped if desirable. + +--- + +Also see the following implementation PRs: +* [facebook/react/pull/12745](https://github.com/facebook/react/pull/12745): Add `Profiler` component and tests +* [facebook/react/pull/12852](https://github.com/facebook/react/pull/12852): Add start and stop time params +* [facebook/react/pull/12886](https://github.com/facebook/react/pull/12886): Add production + profiling bundle for ReactDOM and ReactNative + +# Drawbacks + +Overuse of this component might negatively impact application performance. + +# Alternatives + +None considered. + +# Adoption strategy + +This is an entirely new component. Adoption can be organic and gradual. + +# How we teach this + +A reactjs.org blog post would be a good initial start. + +# Unresolved questions + +How will people use this/ \ No newline at end of file From dfe022fa05687ec21c180b8ede77bbc23061b1af Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Tue, 22 May 2018 14:34:48 -0700 Subject: [PATCH 02/12] Unresolved questions --- text/0000-profiler.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/text/0000-profiler.md b/text/0000-profiler.md index 152691f5..6c97a6a4 100644 --- a/text/0000-profiler.md +++ b/text/0000-profiler.md @@ -126,4 +126,6 @@ A reactjs.org blog post would be a good initial start. # Unresolved questions -How will people use this/ \ No newline at end of file +How will people use this? The current proposal is kind of low level and would probably benefit from some reusable abstractions being built on top of it that e.g. aggregate/batch render timings. + +How will this feature integrate with React DevTools? I have some ideas but nothing concrete yet to share. \ No newline at end of file From 58afaa12e08dc174f08edeb7c3d434bb5358c14e Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Tue, 22 May 2018 14:39:03 -0700 Subject: [PATCH 03/12] Formatting nits --- text/0000-profiler.md | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/text/0000-profiler.md b/text/0000-profiler.md index 6c97a6a4..3c6b49b8 100644 --- a/text/0000-profiler.md +++ b/text/0000-profiler.md @@ -69,14 +69,14 @@ Timing measurements should also be significantly lighter weight than the current The `onRender` callback is called each time a component within the `Profiler` renders. It receives the following parameters: ```js function onRenderCallback( - id, - phase, - actualTime, - baseTime, - startTime, - commitTime -) { - // Aggregate or log render timings + id: string, + phaseL "mount" | "update", + actualTime: number, + baseTime: number, + startTime: number, + commitTime: number +): void { + // Aggregate or log render timings... } ``` @@ -101,13 +101,6 @@ Start time isn't just the commit time less the "actual" time, because in async r #### `commitTime: number` Commit time could be roughly determined using e.g. `performance.now()` within the `onRender` callback, but multiple `Profiler` components would end up with slightly different times for a single commit. Instead, an explicit time is provided (shared between all `Profiler`s in the commit) enabling them to be grouped if desirable. ---- - -Also see the following implementation PRs: -* [facebook/react/pull/12745](https://github.com/facebook/react/pull/12745): Add `Profiler` component and tests -* [facebook/react/pull/12852](https://github.com/facebook/react/pull/12852): Add start and stop time params -* [facebook/react/pull/12886](https://github.com/facebook/react/pull/12886): Add production + profiling bundle for ReactDOM and ReactNative - # Drawbacks Overuse of this component might negatively impact application performance. From b5296133dcd79cea337da1cad78feb24fcc571e5 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Tue, 22 May 2018 14:43:32 -0700 Subject: [PATCH 04/12] Organizational tweask --- text/0000-profiler.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/text/0000-profiler.md b/text/0000-profiler.md index 3c6b49b8..b23cb559 100644 --- a/text/0000-profiler.md +++ b/text/0000-profiler.md @@ -117,8 +117,10 @@ This is an entirely new component. Adoption can be organic and gradual. A reactjs.org blog post would be a good initial start. -# Unresolved questions +Perhaps we could provide some sort of discoverability within React DevTools. -How will people use this? The current proposal is kind of low level and would probably benefit from some reusable abstractions being built on top of it that e.g. aggregate/batch render timings. +# Unresolved questions -How will this feature integrate with React DevTools? I have some ideas but nothing concrete yet to share. \ No newline at end of file +* How will people use this? The current proposal is kind of low level and would probably benefit from some reusable abstractions being built on top of it that e.g. aggregate/batch render timings. +* Are the proposed timing metrics sufficiently useful? +* How will this feature integrate with React DevTools? I have some ideas but nothing concrete yet to share. \ No newline at end of file From 1475772c1db1b04e4d0df2bd931cf8db2d18c63a Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Tue, 22 May 2018 15:04:06 -0700 Subject: [PATCH 05/12] Added an async caveat about actual time --- text/0000-profiler.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/text/0000-profiler.md b/text/0000-profiler.md index b23cb559..c9a8b9d2 100644 --- a/text/0000-profiler.md +++ b/text/0000-profiler.md @@ -88,7 +88,9 @@ The `id` value of the `Profiler` tag that was measured. This value can change be Either the string "mount" or "update" (depending on whether this root was newly mounted or has just been updated). #### `actualTime: number` -Time spent rendering the `Profiler` and its descendants for the current (most recent recent) update. This time tells us how well the subtree makes use of `shouldComponentUpdate` for memoization. Ideally, this time should decrease significantly after the initial mount. +Time spent rendering the `Profiler` and its descendants for the current (most recent recent) update. This time tells us how well the subtree makes use of `shouldComponentUpdate` for memoization. + +Ideally, this time should decrease significantly after the initial mount. Althoguh in async mode, under certain conditions, React might render the same component more than once as part of a single commit. (In this event, the "actual" time for an update might be larger than the initial time.) #### `baseTime: number` Duration of the most recent `render` time for each individual component within the `Profiler` tree. This reflects a worst-case cost of rendering (e.g. the initial mount or no `shouldComponentUpdate` memoization). From 7cb55e659d9c1be93b725e5be8c0b6a6d38fa4f6 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Tue, 22 May 2018 15:07:06 -0700 Subject: [PATCH 06/12] Typofix --- text/0000-profiler.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-profiler.md b/text/0000-profiler.md index c9a8b9d2..5d299e0f 100644 --- a/text/0000-profiler.md +++ b/text/0000-profiler.md @@ -70,7 +70,7 @@ The `onRender` callback is called each time a component within the `Profiler` re ```js function onRenderCallback( id: string, - phaseL "mount" | "update", + phase: "mount" | "update", actualTime: number, baseTime: number, startTime: number, From 3e9edf1d75aaef80d8284ca94c4850d463dfef54 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Tue, 22 May 2018 15:32:59 -0700 Subject: [PATCH 07/12] Added clarfiication note about how works in production bundle --- text/0000-profiler.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-profiler.md b/text/0000-profiler.md index 5d299e0f..a366d339 100644 --- a/text/0000-profiler.md +++ b/text/0000-profiler.md @@ -62,7 +62,7 @@ Although `Profiler` is a light-weight component, it should be used only when nec It is important that render timing metrics work properly with React's experimental async rendering mode. When asynchronously rendering, React may yield periodically so that an app remains responsive even on low-powered devices. This yielded time (when React is not running) should not be included when considering the "cost" of a render. This distinction is not possible to implement this in user space. -Timing measurements should also be significantly lighter weight than the current User Timing API so that they can be gathered in production without negatively impacting user experience. (The User Timing API is currently disabled for production because it is slow.) In addition to a faster implementation, we can further limit the impact on existing apps by creating a new production + profiling bundle. This way, apps that don't make use of the `Profiler` component (or wish to disable it globally) will not incur any additional overhead. +Timing measurements should also be significantly lighter weight than the current User Timing API so that they can be gathered in production without negatively impacting user experience. (The User Timing API is currently disabled for production because it is slow.) In addition to a faster implementation, we can further limit the impact on existing apps by creating a new production + profiling bundle. This way, apps that don't make use of the `Profiler` component (or wish to disable it globally) will not incur any additional overhead. (The `Profiler` component will render its children in production mode but its `onRender` callback will not be called.) # Detailed design From 6062c5222ffe8574e8bc6ef5f4019d8d323e1884 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Sat, 9 Jun 2018 10:53:35 -0700 Subject: [PATCH 08/12] Typofix --- text/0000-profiler.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/text/0000-profiler.md b/text/0000-profiler.md index a366d339..f113211f 100644 --- a/text/0000-profiler.md +++ b/text/0000-profiler.md @@ -60,7 +60,7 @@ Although `Profiler` is a light-weight component, it should be used only when nec # Motivation -It is important that render timing metrics work properly with React's experimental async rendering mode. When asynchronously rendering, React may yield periodically so that an app remains responsive even on low-powered devices. This yielded time (when React is not running) should not be included when considering the "cost" of a render. This distinction is not possible to implement this in user space. +It is important that render timing metrics work properly with React's experimental async rendering mode. When asynchronously rendering, React may yield periodically so that an app remains responsive even on low-powered devices. This yielded time (when React is not running) should not be included when considering the "cost" of a render. This distinction is not possible to implement in user space. Timing measurements should also be significantly lighter weight than the current User Timing API so that they can be gathered in production without negatively impacting user experience. (The User Timing API is currently disabled for production because it is slow.) In addition to a faster implementation, we can further limit the impact on existing apps by creating a new production + profiling bundle. This way, apps that don't make use of the `Profiler` component (or wish to disable it globally) will not incur any additional overhead. (The `Profiler` component will render its children in production mode but its `onRender` callback will not be called.) @@ -125,4 +125,4 @@ Perhaps we could provide some sort of discoverability within React DevTools. * How will people use this? The current proposal is kind of low level and would probably benefit from some reusable abstractions being built on top of it that e.g. aggregate/batch render timings. * Are the proposed timing metrics sufficiently useful? -* How will this feature integrate with React DevTools? I have some ideas but nothing concrete yet to share. \ No newline at end of file +* How will this feature integrate with React DevTools? I have some ideas but nothing concrete yet to share. From b1834f9f758c52b866e1d17d22a212634e2030dc Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Fri, 3 Aug 2018 08:30:03 -0700 Subject: [PATCH 09/12] Renamed actualTime -> actualDuration and baseTime -> baseDuration --- text/0000-profiler.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/text/0000-profiler.md b/text/0000-profiler.md index f113211f..1e2ab9bb 100644 --- a/text/0000-profiler.md +++ b/text/0000-profiler.md @@ -71,8 +71,8 @@ The `onRender` callback is called each time a component within the `Profiler` re function onRenderCallback( id: string, phase: "mount" | "update", - actualTime: number, - baseTime: number, + actualDuration: number, + baseDuration: number, startTime: number, commitTime: number ): void { @@ -87,12 +87,12 @@ The `id` value of the `Profiler` tag that was measured. This value can change be #### `phase: "mount" | "update"` Either the string "mount" or "update" (depending on whether this root was newly mounted or has just been updated). -#### `actualTime: number` +#### `actualDuration: number` Time spent rendering the `Profiler` and its descendants for the current (most recent recent) update. This time tells us how well the subtree makes use of `shouldComponentUpdate` for memoization. Ideally, this time should decrease significantly after the initial mount. Althoguh in async mode, under certain conditions, React might render the same component more than once as part of a single commit. (In this event, the "actual" time for an update might be larger than the initial time.) -#### `baseTime: number` +#### `baseDuration: number` Duration of the most recent `render` time for each individual component within the `Profiler` tree. This reflects a worst-case cost of rendering (e.g. the initial mount or no `shouldComponentUpdate` memoization). #### `startTime: number` From c26344547414155ba6bfbc5fd7b4d20ba3f6e9e4 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Fri, 3 Aug 2018 08:31:08 -0700 Subject: [PATCH 10/12] Updated note about Profiler experimental release --- text/0000-profiler.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-profiler.md b/text/0000-profiler.md index 1e2ab9bb..01605816 100644 --- a/text/0000-profiler.md +++ b/text/0000-profiler.md @@ -6,7 +6,7 @@ New React profiling component that collects timing information in order to measure the "cost" of rendering. -(Note that an experimental release of this component is currently slated for 16.4 as `React.unstable_Profiler`.) +Note that an experimental release of this component is available in version 16.4 as `React.unstable_Profiler`. # Basic example From a5c38f465c3aba223bc7ceebfc673bdfa25e4ceb Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Fri, 3 Aug 2018 08:54:18 -0700 Subject: [PATCH 11/12] Added interaction-tracking proposal to RFC --- text/0000-profiler.md | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/text/0000-profiler.md b/text/0000-profiler.md index 01605816..21a86af5 100644 --- a/text/0000-profiler.md +++ b/text/0000-profiler.md @@ -6,9 +6,11 @@ New React profiling component that collects timing information in order to measure the "cost" of rendering. -Note that an experimental release of this component is available in version 16.4 as `React.unstable_Profiler`. +This component will also integrate with the [experimental `interaction-tracking` API](https://github.com/facebook/react/pull/13234) so that tracked interactions can be correlated with the render(s) they cause. This enables the calculation of "wall time" (elapsed real time) from when e.g. a user clicks a form button until when the DOM is updated in response. It also enables long-running renders to be more easily attributed and reproduced. -# Basic example +Note that an experimental release of the profiler component is available in version 16.4 as `React.unstable_Profiler`. It does not yet support interactions as that package has not been released. + +# Usage example `Profiler` can be declared anywhere within a React tree to measure the cost of rendering that portion of the tree. @@ -74,7 +76,8 @@ function onRenderCallback( actualDuration: number, baseDuration: number, startTime: number, - commitTime: number + commitTime: number, + interactions: Array<{ name: string, timestamp: number }>, ): void { // Aggregate or log render timings... } @@ -85,15 +88,17 @@ function onRenderCallback( The `id` value of the `Profiler` tag that was measured. This value can change between renders if e.g. it is derived from `state` or `props`. #### `phase: "mount" | "update"` -Either the string "mount" or "update" (depending on whether this root was newly mounted or has just been updated). +Identifies whether this component has just been mounted or re-rendered due to a change in `state` or `props`. #### `actualDuration: number` Time spent rendering the `Profiler` and its descendants for the current (most recent recent) update. This time tells us how well the subtree makes use of `shouldComponentUpdate` for memoization. -Ideally, this time should decrease significantly after the initial mount. Althoguh in async mode, under certain conditions, React might render the same component more than once as part of a single commit. (In this event, the "actual" time for an update might be larger than the initial time.) +Ideally, this time should decrease significantly after the initial mount as many of the descendants will only need to re-render if their specific `props` change. + +Note that in async mode, under certain conditions, React might render the same component more than once as part of a single commit. (In this event, the "actual" time for an update might be larger than the initial time.) #### `baseDuration: number` -Duration of the most recent `render` time for each individual component within the `Profiler` tree. This reflects a worst-case cost of rendering (e.g. the initial mount or no `shouldComponentUpdate` memoization). +Duration of the most recent `render` time for each individual component within the `Profiler` tree. In other words, this value will only change when a component is re-rendered. It reflects a worst-case cost of rendering (e.g. the initial mount or no `shouldComponentUpdate` memoization). #### `startTime: number` Start time identifies when a particular commit started rendering. Although insufficient to determine the cause of the render, it can at least be used to rule out certain interactions (e.g. mouse click, Flux action). This may be helpful if you are also collecting other types of interactions and trying to correlate them with renders. @@ -103,6 +108,11 @@ Start time isn't just the commit time less the "actual" time, because in async r #### `commitTime: number` Commit time could be roughly determined using e.g. `performance.now()` within the `onRender` callback, but multiple `Profiler` components would end up with slightly different times for a single commit. Instead, an explicit time is provided (shared between all `Profiler`s in the commit) enabling them to be grouped if desirable. +#### `interactions: Array<{ name: string, timestamp: number }>` +An array of interactions that were being tracked (via the `interaction-tracking` package) when this commit was initially scheduled (e.g. when `render` or `setState` were called). + +In the event of a cascading render (e.g. an update scheduled from `componentDidMount` or `componentDidUpdate`) React will forward these interactions along to the subsequent `onRender` calls. + # Drawbacks Overuse of this component might negatively impact application performance. @@ -121,8 +131,7 @@ A reactjs.org blog post would be a good initial start. Perhaps we could provide some sort of discoverability within React DevTools. -# Unresolved questions +# Related proposals -* How will people use this? The current proposal is kind of low level and would probably benefit from some reusable abstractions being built on top of it that e.g. aggregate/batch render timings. -* Are the proposed timing metrics sufficiently useful? -* How will this feature integrate with React DevTools? I have some ideas but nothing concrete yet to share. +* [facebook/react/pull/13253](https://github.com/facebook/react/pull/13253): Integration with the proposed `interaction-tracking` package +* [facebook/react-devtools/pull/1069](https://github.com/facebook/react-devtools/pull/1069): Integration with React DevTools \ No newline at end of file From 009a0b4d0963bc748393d17f434b07f4b0d2f769 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Mon, 22 Jul 2019 14:30:07 -0700 Subject: [PATCH 12/12] Udpated RFC --- text/0000-profiler.md | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/text/0000-profiler.md b/text/0000-profiler.md index 21a86af5..b1784bf8 100644 --- a/text/0000-profiler.md +++ b/text/0000-profiler.md @@ -8,7 +8,7 @@ New React profiling component that collects timing information in order to measu This component will also integrate with the [experimental `interaction-tracking` API](https://github.com/facebook/react/pull/13234) so that tracked interactions can be correlated with the render(s) they cause. This enables the calculation of "wall time" (elapsed real time) from when e.g. a user clicks a form button until when the DOM is updated in response. It also enables long-running renders to be more easily attributed and reproduced. -Note that an experimental release of the profiler component is available in version 16.4 as `React.unstable_Profiler`. It does not yet support interactions as that package has not been released. +Note that an experimental release of the `Profiler` component was first included with version 16.4 as `React.unstable_Profiler`. It did not yet support interaction tracing as that package had not been released. # Usage example @@ -58,11 +58,11 @@ render( ); ``` -Although `Profiler` is a light-weight component, it should be used only when necessary; each use adds CPU and memory overhead to an application. +Although `Profiler` is a light-weight component, it should be used only when necessary; each use adds some CPU and memory overhead to an application. # Motivation -It is important that render timing metrics work properly with React's experimental async rendering mode. When asynchronously rendering, React may yield periodically so that an app remains responsive even on low-powered devices. This yielded time (when React is not running) should not be included when considering the "cost" of a render. This distinction is not possible to implement in user space. +It is important for render timing metrics to work properly with React's experimental concurrent rendering mode. In concurrent mode, React may yield to the browser periodically so that an app remains responsive even on low-powered devices. This yielded time (when React is not running) should not be included when considering the "cost" of a render. This distinction is not possible to implement in user space. Timing measurements should also be significantly lighter weight than the current User Timing API so that they can be gathered in production without negatively impacting user experience. (The User Timing API is currently disabled for production because it is slow.) In addition to a faster implementation, we can further limit the impact on existing apps by creating a new production + profiling bundle. This way, apps that don't make use of the `Profiler` component (or wish to disable it globally) will not incur any additional overhead. (The `Profiler` component will render its children in production mode but its `onRender` callback will not be called.) @@ -77,7 +77,7 @@ function onRenderCallback( baseDuration: number, startTime: number, commitTime: number, - interactions: Array<{ name: string, timestamp: number }>, + interactions: Set<{ name: string, timestamp: number }>, ): void { // Aggregate or log render timings... } @@ -91,14 +91,14 @@ The `id` value of the `Profiler` tag that was measured. This value can change be Identifies whether this component has just been mounted or re-rendered due to a change in `state` or `props`. #### `actualDuration: number` -Time spent rendering the `Profiler` and its descendants for the current (most recent recent) update. This time tells us how well the subtree makes use of `shouldComponentUpdate` for memoization. +Time spent rendering the `Profiler` and its descendants for the current (most recent recent) update. This time tells us how well the subtree makes use of memoization (e.g. `React.memo`, `useMemo`, `shouldComponentUpdate`). Ideally, this time should decrease significantly after the initial mount as many of the descendants will only need to re-render if their specific `props` change. Note that in async mode, under certain conditions, React might render the same component more than once as part of a single commit. (In this event, the "actual" time for an update might be larger than the initial time.) #### `baseDuration: number` -Duration of the most recent `render` time for each individual component within the `Profiler` tree. In other words, this value will only change when a component is re-rendered. It reflects a worst-case cost of rendering (e.g. the initial mount or no `shouldComponentUpdate` memoization). +Duration of the most recent `render` time for each individual component within the `Profiler` tree. In other words, this value will only change when a component is re-rendered. It reflects a worst-case cost of rendering (e.g. the initial mount or a tree with no memoization). #### `startTime: number` Start time identifies when a particular commit started rendering. Although insufficient to determine the cause of the render, it can at least be used to rule out certain interactions (e.g. mouse click, Flux action). This may be helpful if you are also collecting other types of interactions and trying to correlate them with renders. @@ -109,9 +109,9 @@ Start time isn't just the commit time less the "actual" time, because in async r Commit time could be roughly determined using e.g. `performance.now()` within the `onRender` callback, but multiple `Profiler` components would end up with slightly different times for a single commit. Instead, an explicit time is provided (shared between all `Profiler`s in the commit) enabling them to be grouped if desirable. #### `interactions: Array<{ name: string, timestamp: number }>` -An array of interactions that were being tracked (via the `interaction-tracking` package) when this commit was initially scheduled (e.g. when `render` or `setState` were called). +Set of interactions that were being tracked (via the `interaction-tracking` package) when this commit was initially scheduled (e.g. when `render` or `setState` were called). -In the event of a cascading render (e.g. an update scheduled from `componentDidMount` or `componentDidUpdate`) React will forward these interactions along to the subsequent `onRender` calls. +In the event of a cascading render (e.g. an update scheduled from an effect or `componentDidMount`/`componentDidUpdate`) React will forward these interactions along to the subsequent `onRender` calls. # Drawbacks @@ -134,4 +134,8 @@ Perhaps we could provide some sort of discoverability within React DevTools. # Related proposals * [facebook/react/pull/13253](https://github.com/facebook/react/pull/13253): Integration with the proposed `interaction-tracking` package -* [facebook/react-devtools/pull/1069](https://github.com/facebook/react-devtools/pull/1069): Integration with React DevTools \ No newline at end of file +* [facebook/react-devtools/pull/1069](https://github.com/facebook/react-devtools/pull/1069): Integration with React DevTools + +# Related documentation +* [fb.me/react-profiling](http://fb.me/react-profiling): Instructions for profiling in production +* [fb.me/react-interaction-tracing](http://fb.me/react-interaction-tracing): Instructions for using interaction tracing with React \ No newline at end of file