2017-03-24 1 views
6

HintergrundDiagnostizieren Auslöser Range: Maximale Call-Stack-Größe überschritten in React KeyEscapeUtils

Unsere Webapp mit Reagieren und Redux mit den offiziellen reagieren-redux Bindungen geschrieben. Eine andere primäre Bibliothek, die in dieser Web-App verwendet wird, ist . Wir haben dies kürzlich in eine Redux-App umgewandelt, obwohl es seit einiger Zeit React verwendet.

Das Problem

manchmal Refreshing (in der Regel jeden zweiten Refresh) verursacht eine

RangeError: Maximum call stack size exceeded 
at String.replace (<anonymous>) 
at Object.unescape (KeyEscapeUtils.js:49) 
at flattenSingleChildIntoContext (flattenChildren.js:32) 
at flattenChildren.js:53 
at traverseAllChildrenImpl (traverseAllChildren.js:69) 
at traverseAllChildrenImpl (traverseAllChildren.js:85) 
at traverseAllChildren (traverseAllChildren.js:157) 
at flattenChildren (flattenChildren.js:52) 
at ReactDOMComponent._reconcilerUpdateChildren (ReactMultiChild.js:209) 
at ReactDOMComponent._updateChildren (ReactMultiChild.js:315) 

Hier ist der Quellcode Reagieren wo es versagt:

return ('' + keySubstring).replace(unescapeRegex, function (match) { 
    return unescaperLookup[match]; 
}); 

und im Kontext:

/** 
* Unescape and unwrap key for human-readable display 
* 
* @param {string} key to unescape. 
* @return {string} the unescaped key. 
*/ 
function unescape(key) { 
    var unescapeRegex = /(=0|=2)/g; 
    var unescaperLookup = { 
    '=0': '=', 
    '=2': ':' 
    }; 
    var keySubstring = key[0] === '.' && key[1] === '$' ? key.substring(2) : key.substring(1); 

    return ('' + keySubstring).replace(unescapeRegex, function (match) { 
    return unescaperLookup[match]; 
    }); 
} 

Dies ist wahrscheinlich indikativ, dass ich irgendwo Reagieren in meinem Code missbrauche, aber da das Stacktrace keine Verweise auf meinen eigenen Code enthält, bin ich mir nicht sicher, wonach ich suchen soll. Es scheint eine Endlosschleife des erneuten Renderns zu sein, und ich bin verdächtig, dass es möglicherweise auf einen falsch platzierten Aufruf von setState zurückzuführen ist.

Die Frage

wahrscheinlich mein Verdacht ist? Wie kann ich dieses Problem weiter diagnostizieren, da meine eigene Codebasis ziemlich umfangreich ist? Was bedeutet es, dass dies in KeyEscapeUtils fehlgeschlagen ist?

+0

Können Sie angeben, wo diese Funktion verwendet wird, idealerweise die gesamte Komponente, die sie verwendet? Die Quelle des Fehlers ist höchstwahrscheinlich höher. –

Antwort

2

Ich glaube nicht, dass der Ort, an dem es fehlgeschlagen ist, signifikant ist, da Sie scheinbar in einer Endlosschleife gefangen sind, und dies ist nur der Punkt, an dem das Call Stack Limit überschritten wird.

Um zu diagnostizieren, würde ich versuchen, ‚auf Ausnahmen Pause‘ einschalten in Chrom Entwickler-Tools, wenn es nicht bereits ist, und sucht weiter den Stack-Trace für Ihren eigenen Code, wenn es Pausen.

Sie haben Recht, dass unsachgemäße setState-Aufrufe dies verursachen könnten. Zum Beispiel, wenn Sie in ComponentDidUpdate setState nicht aktiviert haben oder rendern. Es ist seltsam, dass es nur manchmal passiert.

+0

Es war tatsächlich ein Aufruf von 'setState' in' componentDidUpdate'. Ich konnte identifizieren, welche Komponente der Täter war, indem ich die React-Komponenten kommentierte, bis ich das Problem isoliert hatte. Eine kursorische Überprüfung aller 'componentDidUpdates' ist ebenfalls ein guter Anfang. –

3

Ich suchte nach unescape durch den Quellcode von React (Version 15.4) und habe nur eine Stelle gefunden, wo es verwendet wird. Die Datei ist react/lib/flattenChildren.js:

function flattenSingleChildIntoContext(traverseContext, child, name, selfDebugID) { 
    // We found a component instance. 
    if (traverseContext && typeof traverseContext === 'object') { 
    var result = traverseContext; 
    var keyUnique = result[name] === undefined; 
    if (process.env.NODE_ENV !== 'production') { 
     if (!ReactComponentTreeHook) { 
     ReactComponentTreeHook = require('./ReactComponentTreeHook'); 
     } 
     if (!keyUnique) { 
     process.env.NODE_ENV !== 'production' ? warning(false, 'flattenChildren(...): Encountered two children with the same key, ' + '`%s`. Child keys must be unique; when two children share a key, only ' + 'the first child will be used.%s', KeyEscapeUtils.unescape(name), ReactComponentTreeHook.getStackAddendumByID(selfDebugID)) : void 0; 
     } 
    } 
    if (keyUnique && child != null) { 
     result[name] = child; 
    } 
    } 
} 

Es ist in den flattenSingleChildIntoContext - genau, wie es in Ihrem Stack-Trace angezeigt wird. Die Linie mit dem Problem versucht, eine Warnung an zeigen:

process.env.NODE_ENV !== 'production' ? warning(false, 'flattenChildren(...): Encountered two children with the same key, ' + '`%s`. Child keys must be unique; when two children share a key, only ' + 'the first child will be used.%s', KeyEscapeUtils.unescape(name), ReactComponentTreeHook.getStackAddendumByID(selfDebugID)) : void 0; 

Es bedeutet, dass die maximalen Call-Stack Fehler nur im Entwicklungsmodus auftritt. Das Problem ist, dass Sie irgendwo zwei oder mehr Elemente mit demselben Schlüssel rendern. Um zu wissen, welcher Schlüssel das ist, können Sie den Haltepunkt in dieser Zeile in Chrome Dev Tools verwenden.Oder Sie können console.log dort hinzufügen und Ausnahme auslösen, so dass er die Ausführung hält direkt dort:

if (!keyUnique) { 
    console.log('key is not unique', name); 
    throw new Error('Key is not unique'); 
    } 

Wenn Sie den Schlüssel auf diese Weise erhalten Sie in der Lage sein, den Ort zu finden, wo Sie Elemente mit doppelten Schlüssel haben.

Verwandte Themen