[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(); 

} 

// ... 

} 

```
This commit is contained in:
Mofei Zhang
2023-05-17 14:39:26 -04:00
parent dc603bb2fa
commit bceb786c5a
+52
View File
@@ -12,6 +12,7 @@ const {
ReactCurrentDispatcher,
},
useRef,
useEffect,
} = React;
export const $empty = Symbol.for("react.memo_cache_sentinel");
@@ -89,3 +90,54 @@ export function $reset($) {
export function $makeReadOnly() {
throw new Error("TODO: implement $makeReadOnly in react-forget-runtime");
}
/**
* Instrumentation to count rerenders in React components
*/
export const renderCounterRegistry /*: Map<string,Set<{count: number}>>*/ =
new Map();
export function clearRenderCounterRegistry() {
for (const counters of renderCounterRegistry.values()) {
counters.forEach((counter) => {
counter.count = 0;
});
}
}
function registerRenderCounter(name, val) {
let counters = renderCounterRegistry.get(name);
if (counters == null) {
counters = new Set();
renderCounterRegistry.set(name, counters);
}
counters.add(val);
}
function removeRenderCounter(name, val): void {
const counters = renderCounterRegistry.get(name);
if (counters == null) {
return;
}
counters.delete(val);
}
export function useRenderCounter(name): void {
const val = useRef(null);
if (val.current != null) {
val.current.count += 1;
}
useEffect(() => {
// Not counting initial render shouldn't be a problem
if (val.current == null) {
const counter = { count: 0 };
registerRenderCounter(name, counter);
val.current = counter;
}
return () => {
if (val.current !== null) {
removeRenderCounter(name, val.current);
}
};
});
}