[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
+}