@samitouri / QOS-React-2 / commits / bceb786c5a

[runtime] useRenderCounter

--- (`react-forget-runtime` package seems to be synced to -.) RFC: useRenderCounter hook: - tracks # renders (increments on render path) - exposes a global renderCounterRegistry (counting # renders in alive / mounted components) Next PR will modify BabelPlugin to add codegen ```js // Similar to how we're currently importing `isForgetEnabled` import {isInstrumentForgetEnabled_Secret} from "ReactForgetFeatureFlag"; // ... function Component_uncompiled(props) { if (isInstrumentForgetEnabled_Secret) { useRenderCounter(); } // ... } function Component_forget(props) { if (isInstrumentForgetEnabled_Secret) { useRenderCounter(); } // ... } ```

Mofei Zhang committed May 17, 2023 at 14:39 UTC bceb786c5aad621d9f6c2ee4dd3c04fe921919bb
1 file changed +52
compiler/forget/packages/react-forget-runtime/index.js
+52
@@ -12,6 +12,7 @@ const {
12 ReactCurrentDispatcher,
13 },
14 useRef,
15 + useEffect,
16 } = React;
17
18 export const $empty = Symbol.for("react.memo_cache_sentinel");
@@ -89,3 +90,54 @@ export function $reset($) {
90 export function $makeReadOnly() {
91 throw new Error("TODO: implement $makeReadOnly in react-forget-runtime");
92 }
93 +
94 +/**
95 + * Instrumentation to count rerenders in React components
96 + */
97 +export const renderCounterRegistry /*: Map<string,Set<{count: number}>>*/ =
98 + new Map();
99 +export function clearRenderCounterRegistry() {
100 + for (const counters of renderCounterRegistry.values()) {
101 + counters.forEach((counter) => {
102 + counter.count = 0;
103 + });
104 + }
105 +}
106 +
107 +function registerRenderCounter(name, val) {
108 + let counters = renderCounterRegistry.get(name);
109 + if (counters == null) {
110 + counters = new Set();
111 + renderCounterRegistry.set(name, counters);
112 + }
113 + counters.add(val);
114 +}
115 +
116 +function removeRenderCounter(name, val): void {
117 + const counters = renderCounterRegistry.get(name);
118 + if (counters == null) {
119 + return;
120 + }
121 + counters.delete(val);
122 +}
123 +
124 +export function useRenderCounter(name): void {
125 + const val = useRef(null);
126 +
127 + if (val.current != null) {
128 + val.current.count += 1;
129 + }
130 + useEffect(() => {
131 + // Not counting initial render shouldn't be a problem
132 + if (val.current == null) {
133 + const counter = { count: 0 };
134 + registerRenderCounter(name, counter);
135 + val.current = counter;
136 + }
137 + return () => {
138 + if (val.current !== null) {
139 + removeRenderCounter(name, val.current);
140 + }
141 + };
142 + });
143 +}