diff --git a/packages/shared/ReactComponentStackFrame.js b/packages/shared/ReactComponentStackFrame.js index 3906504caabd..e1420e475e2e 100644 --- a/packages/shared/ReactComponentStackFrame.js +++ b/packages/shared/ReactComponentStackFrame.js @@ -53,6 +53,11 @@ export function describeBuiltInComponentFrame( } let reentry = false; +let componentFrameCache; +if (__DEV__) { + const PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map; + componentFrameCache = new PossiblyWeakMap(); +} export function describeNativeComponentFrame( fn: Function, @@ -63,6 +68,13 @@ export function describeNativeComponentFrame( return ''; } + if (__DEV__) { + const frame = componentFrameCache.get(fn); + if (frame !== undefined) { + return frame; + } + } + const control = Error(); reentry = true; @@ -119,7 +131,11 @@ export function describeNativeComponentFrame( if (sampleLines[s] !== controlLines[c]) { // Return the line we found. // V8 adds a "new" prefix for native classes. Let's remove it to make it prettier. - return '\n' + sampleLines[s - 1].replace(' at new ', ' at '); + const frame = '\n' + sampleLines[s - 1].replace(' at new ', ' at '); + if (__DEV__) { + componentFrameCache.set(fn, frame); + } + return frame; } } } @@ -132,7 +148,11 @@ export function describeNativeComponentFrame( } // Fallback to just using the name if we couldn't make it throw. const name = fn ? fn.displayName || fn.name : ''; - return name ? describeBuiltInComponentFrame(name) : ''; + const syntheticFrame = name ? describeBuiltInComponentFrame(name) : ''; + if (__DEV__) { + componentFrameCache.set(fn, syntheticFrame); + } + return syntheticFrame; } const BEFORE_SLASH_RE = /^(.*)[\\\/]/;