Teact: Fix memory leak due to missing effect cleanups

This commit is contained in:
Alexander Zinchuk 2022-05-06 17:56:04 +01:00
parent 6f418f3e26
commit f91960b90c

View File

@ -378,12 +378,14 @@ function unmountComponent(componentInstance: ComponentInstance) {
memoContainer.current = undefined; memoContainer.current = undefined;
}); });
componentInstance.hooks.effects.byCursor.forEach(({ cleanup }) => { componentInstance.hooks.effects.byCursor.forEach((effect) => {
if (typeof cleanup === 'function') { if (effect.cleanup) {
try { try {
cleanup(); effect.cleanup();
} catch (err: any) { } catch (err: any) {
handleError(err); handleError(err);
} finally {
effect.cleanup = undefined;
} }
} }
}); });
@ -535,29 +537,33 @@ function useLayoutEffectBase(
} }
const { cleanup } = byCursor[cursor]; const { cleanup } = byCursor[cursor];
if (typeof cleanup === 'function') { if (!cleanup) {
try { return;
// eslint-disable-next-line @typescript-eslint/naming-convention }
let DEBUG_startAt: number | undefined;
if (DEBUG) {
DEBUG_startAt = performance.now();
}
cleanup(); try {
// eslint-disable-next-line @typescript-eslint/naming-convention
if (DEBUG) { let DEBUG_startAt: number | undefined;
const duration = performance.now() - DEBUG_startAt!; if (DEBUG) {
const componentName = componentInstance.name; DEBUG_startAt = performance.now();
if (duration > DEBUG_EFFECT_THRESHOLD) {
// eslint-disable-next-line no-console
console.warn(
`[Teact] Slow cleanup at effect cursor #${cursor}: ${componentName}, ${Math.round(duration)} ms`,
);
}
}
} catch (err: any) {
handleError(err);
} }
cleanup();
if (DEBUG) {
const duration = performance.now() - DEBUG_startAt!;
const componentName = componentInstance.name;
if (duration > DEBUG_EFFECT_THRESHOLD) {
// eslint-disable-next-line no-console
console.warn(
`[Teact] Slow cleanup at effect cursor #${cursor}: ${componentName}, ${Math.round(duration)} ms`,
);
}
}
} catch (err: any) {
handleError(err);
} finally {
byCursor[cursor].cleanup = undefined;
} }
} }
@ -566,13 +572,18 @@ function useLayoutEffectBase(
return; return;
} }
execCleanup();
// eslint-disable-next-line @typescript-eslint/naming-convention // eslint-disable-next-line @typescript-eslint/naming-convention
let DEBUG_startAt: number | undefined; let DEBUG_startAt: number | undefined;
if (DEBUG) { if (DEBUG) {
DEBUG_startAt = performance.now(); DEBUG_startAt = performance.now();
} }
byCursor[cursor].cleanup = effect() as Function; const result = effect();
if (typeof result === 'function') {
byCursor[cursor].cleanup = result;
}
if (DEBUG) { if (DEBUG) {
const duration = performance.now() - DEBUG_startAt!; const duration = performance.now() - DEBUG_startAt!;
@ -616,7 +627,7 @@ function useLayoutEffectBase(
byCursor[cursor] = { byCursor[cursor] = {
effect, effect,
dependencies, dependencies,
cleanup: byCursor[cursor] ? byCursor[cursor].cleanup : undefined, cleanup: byCursor[cursor]?.cleanup,
}; };
renderingInstance.hooks.effects.cursor++; renderingInstance.hooks.effects.cursor++;