diff --git a/src/isomorphic/ReactDebugTool.js b/src/isomorphic/ReactDebugTool.js index 005378b76d76c..f88513b387157 100644 --- a/src/isomorphic/ReactDebugTool.js +++ b/src/isomorphic/ReactDebugTool.js @@ -48,45 +48,54 @@ var currentTimerDebugID = null; var currentTimerStartTime = null; var currentTimerType = null; +function clearHistory() { + ReactComponentTreeDevtool.purgeUnmountedComponents(); + ReactNativeOperationHistoryDevtool.clearHistory(); +} + +function getTreeSnapshot(registeredIDs) { + return registeredIDs.reduce((tree, id) => { + var ownerID = ReactComponentTreeDevtool.getOwnerID(id); + var parentID = ReactComponentTreeDevtool.getParentID(id); + tree[id] = { + displayName: ReactComponentTreeDevtool.getDisplayName(id), + text: ReactComponentTreeDevtool.getText(id), + updateCount: ReactComponentTreeDevtool.getUpdateCount(id), + childIDs: ReactComponentTreeDevtool.getChildIDs(id), + // Text nodes don't have owners but this is close enough. + ownerID: ownerID || ReactComponentTreeDevtool.getOwnerID(parentID), + parentID, + }; + return tree; + }, {}); +} + function resetMeasurements() { if (__DEV__) { + var previousStartTime = currentFlushStartTime; + var previousMeasurements = currentFlushMeasurements || []; + var previousOperations = ReactNativeOperationHistoryDevtool.getHistory(); + if (!isProfiling || currentFlushNesting === 0) { currentFlushStartTime = null; currentFlushMeasurements = null; + clearHistory(); return; } - var previousStartTime = currentFlushStartTime; - var previousMeasurements = currentFlushMeasurements || []; - var previousOperations = ReactNativeOperationHistoryDevtool.getHistory(); - if (previousMeasurements.length || previousOperations.length) { var registeredIDs = ReactComponentTreeDevtool.getRegisteredIDs(); flushHistory.push({ duration: performanceNow() - previousStartTime, measurements: previousMeasurements || [], operations: previousOperations || [], - treeSnapshot: registeredIDs.reduce((tree, id) => { - var ownerID = ReactComponentTreeDevtool.getOwnerID(id); - var parentID = ReactComponentTreeDevtool.getParentID(id); - tree[id] = { - displayName: ReactComponentTreeDevtool.getDisplayName(id), - text: ReactComponentTreeDevtool.getText(id), - updateCount: ReactComponentTreeDevtool.getUpdateCount(id), - childIDs: ReactComponentTreeDevtool.getChildIDs(id), - // Text nodes don't have owners but this is close enough. - ownerID: ownerID || ReactComponentTreeDevtool.getOwnerID(parentID), - parentID, - }; - return tree; - }, {}), + treeSnapshot: getTreeSnapshot(registeredIDs), }); } + clearHistory(); currentFlushStartTime = performanceNow(); currentFlushMeasurements = []; - ReactComponentTreeDevtool.purgeUnmountedComponents(); - ReactNativeOperationHistoryDevtool.clearHistory(); } } diff --git a/src/isomorphic/__tests__/ReactPerf-test.js b/src/isomorphic/__tests__/ReactPerf-test.js index c81a4e82a79d9..644bc618b849f 100644 --- a/src/isomorphic/__tests__/ReactPerf-test.js +++ b/src/isomorphic/__tests__/ReactPerf-test.js @@ -241,6 +241,21 @@ describe('ReactPerf', function() { }); }); + it('should include stats for components unmounted during measurement', function() { + var container = document.createElement('div'); + var measurements = measure(() => { + ReactDOM.render(
, container); + ReactDOM.render(
, container); + }); + expect(ReactPerf.getExclusive(measurements)).toEqual([{ + key: 'Div', + instanceCount: 3, + counts: { ctor: 3, render: 4 }, + durations: { ctor: 3, render: 4 }, + totalDuration: 7, + }]); + }); + it('warns once when using getMeasurementsSummaryMap', function() { var measurements = measure(() => {}); spyOn(console, 'error'); diff --git a/src/isomorphic/devtools/ReactComponentTreeDevtool.js b/src/isomorphic/devtools/ReactComponentTreeDevtool.js index 57e85b39dfc3c..85902c30d09cc 100644 --- a/src/isomorphic/devtools/ReactComponentTreeDevtool.js +++ b/src/isomorphic/devtools/ReactComponentTreeDevtool.js @@ -106,6 +106,11 @@ var ReactComponentTreeDevtool = { }, purgeUnmountedComponents() { + if (ReactComponentTreeDevtool._preventPurging) { + // Should only be used for testing. + return; + } + Object.keys(tree) .filter(id => !tree[id].isMounted) .forEach(purgeDeep); diff --git a/src/isomorphic/devtools/ReactNativeOperationHistoryDevtool.js b/src/isomorphic/devtools/ReactNativeOperationHistoryDevtool.js index 50478cc405d6c..46b8194465db2 100644 --- a/src/isomorphic/devtools/ReactNativeOperationHistoryDevtool.js +++ b/src/isomorphic/devtools/ReactNativeOperationHistoryDevtool.js @@ -23,6 +23,11 @@ var ReactNativeOperationHistoryDevtool = { }, clearHistory() { + if (ReactNativeOperationHistoryDevtool._preventClearing) { + // Should only be used for tests. + return; + } + history = []; }, diff --git a/src/isomorphic/devtools/__tests__/ReactComponentTreeDevtool-test.js b/src/isomorphic/devtools/__tests__/ReactComponentTreeDevtool-test.js index 106307d0d25ac..1c5cdb7049ab0 100644 --- a/src/isomorphic/devtools/__tests__/ReactComponentTreeDevtool-test.js +++ b/src/isomorphic/devtools/__tests__/ReactComponentTreeDevtool-test.js @@ -97,13 +97,20 @@ describe('ReactComponentTreeDevtool', () => { // Ensure the tree is correct on every step. pairs.forEach(([element, expectedTree]) => { currentElement = element; + + // Mount a new tree or update the existing tree. ReactDOM.render(, node); expect(getActualTree()).toEqual(expectedTree); + + // Purging should have no effect + // on the tree we expect to see. ReactComponentTreeDevtool.purgeUnmountedComponents(); expect(getActualTree()).toEqual(expectedTree); }); + + // Unmounting the root node should purge + // the whole subtree automatically. ReactDOM.unmountComponentAtNode(node); - ReactComponentTreeDevtool.purgeUnmountedComponents(); expect(getActualTree()).toBe(undefined); expect(getRootDisplayNames()).toEqual([]); expect(getRegisteredDisplayNames()).toEqual([]); @@ -112,8 +119,23 @@ describe('ReactComponentTreeDevtool', () => { // Ensure the tree is correct on every step. pairs.forEach(([element, expectedTree]) => { currentElement = element; + + // Rendering to string should not produce any entries + // because ReactDebugTool purges it when the flush ends. + ReactDOMServer.renderToString(); + expect(getActualTree()).toBe(undefined); + expect(getRootDisplayNames()).toEqual([]); + expect(getRegisteredDisplayNames()).toEqual([]); + + // To test it, we tell the devtool to ignore next purge + // so the cleanup request by ReactDebugTool is ignored. + // This lets us make assertions on the actual tree. + ReactComponentTreeDevtool._preventPurging = true; ReactDOMServer.renderToString(); + ReactComponentTreeDevtool._preventPurging = false; expect(getActualTree()).toEqual(expectedTree); + + // Purge manually since we skipped the automatic purge. ReactComponentTreeDevtool.purgeUnmountedComponents(); expect(getActualTree()).toBe(undefined); expect(getRootDisplayNames()).toEqual([]); @@ -1631,7 +1653,7 @@ describe('ReactComponentTreeDevtool', () => { assertTreeMatches([element, tree], {includeOwnerDisplayName: true}); }); - it('preserves unmounted components until purge', () => { + it('purges unmounted components automatically', () => { var node = document.createElement('div'); var renderBar = true; var fooInstance; @@ -1666,31 +1688,15 @@ describe('ReactComponentTreeDevtool', () => { renderBar = false; ReactDOM.render(, node); expect( - getTree(barInstance._debugID, { - includeParentDisplayName: true, - expectedParentID: fooInstance._debugID, - }) + getTree(barInstance._debugID, {expectedParentID: null}) ).toEqual({ - displayName: 'Bar', - parentDisplayName: 'Foo', + displayName: 'Unknown', children: [], }); ReactDOM.unmountComponentAtNode(node); expect( - getTree(barInstance._debugID, { - includeParentDisplayName: true, - expectedParentID: fooInstance._debugID, - }) - ).toEqual({ - displayName: 'Bar', - parentDisplayName: 'Foo', - children: [], - }); - - ReactComponentTreeDevtool.purgeUnmountedComponents(); - expect( - getTree(barInstance._debugID, {includeParentDisplayName: true}) + getTree(barInstance._debugID, {expectedParentID: null}) ).toEqual({ displayName: 'Unknown', children: [], @@ -1719,7 +1725,7 @@ describe('ReactComponentTreeDevtool', () => { ReactDOM.unmountComponentAtNode(node); expect(ReactComponentTreeDevtool.getUpdateCount(divID)).toEqual(0); - expect(ReactComponentTreeDevtool.getUpdateCount(spanID)).toEqual(2); + expect(ReactComponentTreeDevtool.getUpdateCount(spanID)).toEqual(0); }); it('does not report top-level wrapper as a root', () => { @@ -1733,12 +1739,6 @@ describe('ReactComponentTreeDevtool', () => { ReactDOM.unmountComponentAtNode(node); expect(getRootDisplayNames()).toEqual([]); - - ReactComponentTreeDevtool.purgeUnmountedComponents(); - expect(getRootDisplayNames()).toEqual([]); - - // This currently contains TopLevelWrapper until purge - // so we only check it at the very end. expect(getRegisteredDisplayNames()).toEqual([]); }); }); diff --git a/src/isomorphic/devtools/__tests__/ReactComponentTreeDevtool-test.native.js b/src/isomorphic/devtools/__tests__/ReactComponentTreeDevtool-test.native.js index 3113d6fcad898..f3b026b459ccf 100644 --- a/src/isomorphic/devtools/__tests__/ReactComponentTreeDevtool-test.native.js +++ b/src/isomorphic/devtools/__tests__/ReactComponentTreeDevtool-test.native.js @@ -119,13 +119,20 @@ describe('ReactComponentTreeDevtool', () => { // Ensure the tree is correct on every step. pairs.forEach(([element, expectedTree]) => { currentElement = element; + + // Mount a new tree or update the existing tree. ReactNative.render(, 1); expect(getActualTree()).toEqual(expectedTree); + + // Purging should have no effect + // on the tree we expect to see. ReactComponentTreeDevtool.purgeUnmountedComponents(); expect(getActualTree()).toEqual(expectedTree); }); + + // Unmounting the root node should purge + // the whole subtree automatically. ReactNative.unmountComponentAtNode(1); - ReactComponentTreeDevtool.purgeUnmountedComponents(); expect(getActualTree()).toBe(undefined); expect(getRootDisplayNames()).toEqual([]); expect(getRegisteredDisplayNames()).toEqual([]); @@ -134,10 +141,13 @@ describe('ReactComponentTreeDevtool', () => { // Ensure the tree is correct on every step. pairs.forEach(([element, expectedTree]) => { currentElement = element; + + // Mount a new tree. ReactNative.render(, 1); - ReactNative.unmountComponentAtNode(1); expect(getActualTree()).toEqual(expectedTree); - ReactComponentTreeDevtool.purgeUnmountedComponents(); + + // Unmounting should clean it up. + ReactNative.unmountComponentAtNode(1); expect(getActualTree()).toBe(undefined); expect(getRootDisplayNames()).toEqual([]); expect(getRegisteredDisplayNames()).toEqual([]); @@ -1620,7 +1630,7 @@ describe('ReactComponentTreeDevtool', () => { assertTreeMatches([element, tree], {includeOwnerDisplayName: true}); }); - it('preserves unmounted components until purge', () => { + it('purges unmounted components automatically', () => { var renderBar = true; var fooInstance; var barInstance; @@ -1654,31 +1664,15 @@ describe('ReactComponentTreeDevtool', () => { renderBar = false; ReactNative.render(, 1); expect( - getTree(barInstance._debugID, { - includeParentDisplayName: true, - expectedParentID: fooInstance._debugID, - }) + getTree(barInstance._debugID, {expectedParentID: null}) ).toEqual({ - displayName: 'Bar', - parentDisplayName: 'Foo', + displayName: 'Unknown', children: [], }); ReactNative.unmountComponentAtNode(1); expect( - getTree(barInstance._debugID, { - includeParentDisplayName: true, - expectedParentID: fooInstance._debugID, - }) - ).toEqual({ - displayName: 'Bar', - parentDisplayName: 'Foo', - children: [], - }); - - ReactComponentTreeDevtool.purgeUnmountedComponents(); - expect( - getTree(barInstance._debugID, {includeParentDisplayName: true}) + getTree(barInstance._debugID, {expectedParentID: null}) ).toEqual({ displayName: 'Unknown', children: [], @@ -1705,7 +1699,7 @@ describe('ReactComponentTreeDevtool', () => { ReactNative.unmountComponentAtNode(1); expect(ReactComponentTreeDevtool.getUpdateCount(viewID)).toEqual(0); - expect(ReactComponentTreeDevtool.getUpdateCount(imageID)).toEqual(2); + expect(ReactComponentTreeDevtool.getUpdateCount(imageID)).toEqual(0); }); it('does not report top-level wrapper as a root', () => { @@ -1717,12 +1711,6 @@ describe('ReactComponentTreeDevtool', () => { ReactNative.unmountComponentAtNode(1); expect(getRootDisplayNames()).toEqual([]); - - ReactComponentTreeDevtool.purgeUnmountedComponents(); - expect(getRootDisplayNames()).toEqual([]); - - // This currently contains TopLevelWrapper until purge - // so we only check it at the very end. expect(getRegisteredDisplayNames()).toEqual([]); }); }); diff --git a/src/isomorphic/devtools/__tests__/ReactNativeOperationHistoryDevtool-test.js b/src/isomorphic/devtools/__tests__/ReactNativeOperationHistoryDevtool-test.js index 73ee7511d1ecb..769fe675b1edc 100644 --- a/src/isomorphic/devtools/__tests__/ReactNativeOperationHistoryDevtool-test.js +++ b/src/isomorphic/devtools/__tests__/ReactNativeOperationHistoryDevtool-test.js @@ -36,9 +36,10 @@ describe('ReactNativeOperationHistoryDevtool', () => { describe('mount', () => { it('gets recorded for native roots', () => { var node = document.createElement('div'); + ReactNativeOperationHistoryDevtool._preventClearing = true; ReactDOM.render(

Hi.

, node); - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); + var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); assertHistoryMatches([{ instanceID: inst._debugID, type: 'mount', @@ -53,7 +54,10 @@ describe('ReactNativeOperationHistoryDevtool', () => { return

Hi.

; } var node = document.createElement('div'); + + ReactNativeOperationHistoryDevtool._preventClearing = true; ReactDOM.render(, node); + var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); assertHistoryMatches([{ instanceID: inst._debugID, @@ -70,6 +74,8 @@ describe('ReactNativeOperationHistoryDevtool', () => { return null; } var node = document.createElement('div'); + + ReactNativeOperationHistoryDevtool._preventClearing = true; ReactDOM.render(, node); // Empty DOM components should be invisible to devtools. @@ -82,11 +88,12 @@ describe('ReactNativeOperationHistoryDevtool', () => { return element; } + ReactNativeOperationHistoryDevtool._preventClearing = true; + var node = document.createElement('div'); element = null; ReactDOM.render(, node); - ReactNativeOperationHistoryDevtool.clearHistory(); element = ; ReactDOM.render(, node); var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); @@ -104,12 +111,14 @@ describe('ReactNativeOperationHistoryDevtool', () => { describe('update styles', () => { it('gets recorded during mount', () => { var node = document.createElement('div'); + + ReactNativeOperationHistoryDevtool._preventClearing = true; ReactDOM.render(
, node); - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); + var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); if (ReactDOMFeatureFlags.useCreateElement) { assertHistoryMatches([{ instanceID: inst._debugID, @@ -138,7 +147,7 @@ describe('ReactNativeOperationHistoryDevtool', () => { ReactDOM.render(
, node); var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - ReactNativeOperationHistoryDevtool.clearHistory(); + ReactNativeOperationHistoryDevtool._preventClearing = true; ReactDOM.render(
, node); ReactDOM.render(
{ ReactDOM.render(
, node); var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - ReactNativeOperationHistoryDevtool.clearHistory(); + ReactNativeOperationHistoryDevtool._preventClearing = true; ReactDOM.render(
{ describe('simple attribute', () => { it('gets recorded during mount', () => { var node = document.createElement('div'); + + ReactNativeOperationHistoryDevtool._preventClearing = true; ReactDOM.render(
, node); - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); + var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); if (ReactDOMFeatureFlags.useCreateElement) { assertHistoryMatches([{ instanceID: inst._debugID, @@ -228,10 +239,11 @@ describe('ReactNativeOperationHistoryDevtool', () => { ReactDOM.render(
, node); var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - ReactNativeOperationHistoryDevtool.clearHistory(); + ReactNativeOperationHistoryDevtool._preventClearing = true; ReactDOM.render(
, node); ReactDOM.render(
, node); ReactDOM.render(
, node); + assertHistoryMatches([{ instanceID: inst._debugID, type: 'update attribute', @@ -262,9 +274,10 @@ describe('ReactNativeOperationHistoryDevtool', () => { ReactDOM.render(
, node); var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - ReactNativeOperationHistoryDevtool.clearHistory(); + ReactNativeOperationHistoryDevtool._preventClearing = true; ReactDOM.render(
, node); ReactDOM.render(
, node); + assertHistoryMatches([{ instanceID: inst._debugID, type: 'update attribute', @@ -280,9 +293,11 @@ describe('ReactNativeOperationHistoryDevtool', () => { describe('custom attribute', () => { it('gets recorded during mount', () => { var node = document.createElement('div'); + + ReactNativeOperationHistoryDevtool._preventClearing = true; ReactDOM.render(
, node); - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); + var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); if (ReactDOMFeatureFlags.useCreateElement) { assertHistoryMatches([{ instanceID: inst._debugID, @@ -312,10 +327,11 @@ describe('ReactNativeOperationHistoryDevtool', () => { ReactDOM.render(
, node); var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - ReactNativeOperationHistoryDevtool.clearHistory(); + ReactNativeOperationHistoryDevtool._preventClearing = true; ReactDOM.render(
, node); ReactDOM.render(
, node); ReactDOM.render(
, node); + assertHistoryMatches([{ instanceID: inst._debugID, type: 'update attribute', @@ -343,9 +359,11 @@ describe('ReactNativeOperationHistoryDevtool', () => { describe('attribute on a web component', () => { it('gets recorded during mount', () => { var node = document.createElement('div'); + + ReactNativeOperationHistoryDevtool._preventClearing = true; ReactDOM.render(, node); - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); + var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); if (ReactDOMFeatureFlags.useCreateElement) { assertHistoryMatches([{ instanceID: inst._debugID, @@ -375,10 +393,11 @@ describe('ReactNativeOperationHistoryDevtool', () => { ReactDOM.render(, node); var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - ReactNativeOperationHistoryDevtool.clearHistory(); + ReactNativeOperationHistoryDevtool._preventClearing = true; ReactDOM.render(, node); ReactDOM.render(, node); ReactDOM.render(, node); + assertHistoryMatches([{ instanceID: inst._debugID, type: 'update attribute', @@ -411,8 +430,9 @@ describe('ReactNativeOperationHistoryDevtool', () => { ReactDOM.render(
Hi.
, node); var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - ReactNativeOperationHistoryDevtool.clearHistory(); + ReactNativeOperationHistoryDevtool._preventClearing = true; ReactDOM.render(
Bye.
, node); + assertHistoryMatches([{ instanceID: inst._debugID, type: 'replace text', @@ -425,8 +445,9 @@ describe('ReactNativeOperationHistoryDevtool', () => { ReactDOM.render(
, node); var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - ReactNativeOperationHistoryDevtool.clearHistory(); + ReactNativeOperationHistoryDevtool._preventClearing = true; ReactDOM.render(
Bye.
, node); + assertHistoryMatches([{ instanceID: inst._debugID, type: 'replace text', @@ -439,8 +460,9 @@ describe('ReactNativeOperationHistoryDevtool', () => { ReactDOM.render(

, node); var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - ReactNativeOperationHistoryDevtool.clearHistory(); + ReactNativeOperationHistoryDevtool._preventClearing = true; ReactDOM.render(
Bye.
, node); + assertHistoryMatches([{ instanceID: inst._debugID, type: 'remove child', @@ -460,8 +482,9 @@ describe('ReactNativeOperationHistoryDevtool', () => { var node = document.createElement('div'); ReactDOM.render(
Hi.
, node); - ReactNativeOperationHistoryDevtool.clearHistory(); + ReactNativeOperationHistoryDevtool._preventClearing = true; ReactDOM.render(
Hi.
, node); + assertHistoryMatches([]); }); }); @@ -473,8 +496,9 @@ describe('ReactNativeOperationHistoryDevtool', () => { var inst1 = ReactDOMComponentTree.getInstanceFromNode(node.firstChild.childNodes[0]); var inst2 = ReactDOMComponentTree.getInstanceFromNode(node.firstChild.childNodes[3]); - ReactNativeOperationHistoryDevtool.clearHistory(); + ReactNativeOperationHistoryDevtool._preventClearing = true; ReactDOM.render(
{'Bye.'}{43}
, node); + assertHistoryMatches([{ instanceID: inst1._debugID, type: 'replace text', @@ -490,8 +514,9 @@ describe('ReactNativeOperationHistoryDevtool', () => { var node = document.createElement('div'); ReactDOM.render(
{'Hi.'}{42}
, node); - ReactNativeOperationHistoryDevtool.clearHistory(); + ReactNativeOperationHistoryDevtool._preventClearing = true; ReactDOM.render(
{'Hi.'}{42}
, node); + assertHistoryMatches([]); }); }); @@ -509,9 +534,11 @@ describe('ReactNativeOperationHistoryDevtool', () => { ReactDOM.render(, node); var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - ReactNativeOperationHistoryDevtool.clearHistory(); element = ; + + ReactNativeOperationHistoryDevtool._preventClearing = true; ReactDOM.render(, node); + assertHistoryMatches([{ instanceID: inst._debugID, type: 'replace with', @@ -528,11 +555,13 @@ describe('ReactNativeOperationHistoryDevtool', () => { var node = document.createElement('div'); element = ; ReactDOM.render(, node); - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - ReactNativeOperationHistoryDevtool.clearHistory(); + var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); element = null; + + ReactNativeOperationHistoryDevtool._preventClearing = true; ReactDOM.render(, node); + assertHistoryMatches([{ instanceID: inst._debugID, type: 'replace with', @@ -550,9 +579,11 @@ describe('ReactNativeOperationHistoryDevtool', () => { element =
; ReactDOM.render(, node); - ReactNativeOperationHistoryDevtool.clearHistory(); element =
; + + ReactNativeOperationHistoryDevtool._preventClearing = true; ReactDOM.render(, node); + assertHistoryMatches([]); }); }); @@ -563,11 +594,12 @@ describe('ReactNativeOperationHistoryDevtool', () => { ReactDOM.render(
Hi.
, node); var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - ReactNativeOperationHistoryDevtool.clearHistory(); + ReactNativeOperationHistoryDevtool._preventClearing = true; ReactDOM.render(
, node ); + assertHistoryMatches([{ instanceID: inst._debugID, type: 'replace children', @@ -583,11 +615,12 @@ describe('ReactNativeOperationHistoryDevtool', () => { ); var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - ReactNativeOperationHistoryDevtool.clearHistory(); + ReactNativeOperationHistoryDevtool._preventClearing = true; ReactDOM.render(
, node ); + assertHistoryMatches([{ instanceID: inst._debugID, type: 'replace children', @@ -600,11 +633,12 @@ describe('ReactNativeOperationHistoryDevtool', () => { ReactDOM.render(

, node); var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - ReactNativeOperationHistoryDevtool.clearHistory(); + ReactNativeOperationHistoryDevtool._preventClearing = true; ReactDOM.render(
, node ); + assertHistoryMatches([{ instanceID: inst._debugID, type: 'remove child', @@ -627,11 +661,12 @@ describe('ReactNativeOperationHistoryDevtool', () => { node ); - ReactNativeOperationHistoryDevtool.clearHistory(); + ReactNativeOperationHistoryDevtool._preventClearing = true; ReactDOM.render(
, node ); + assertHistoryMatches([]); }); }); @@ -642,8 +677,9 @@ describe('ReactNativeOperationHistoryDevtool', () => { ReactDOM.render(
, node); var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - ReactNativeOperationHistoryDevtool.clearHistory(); + ReactNativeOperationHistoryDevtool._preventClearing = true; ReactDOM.render(

, node); + assertHistoryMatches([{ instanceID: inst._debugID, type: 'insert child', @@ -658,8 +694,9 @@ describe('ReactNativeOperationHistoryDevtool', () => { ReactDOM.render(

, node); var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - ReactNativeOperationHistoryDevtool.clearHistory(); + ReactNativeOperationHistoryDevtool._preventClearing = true; ReactDOM.render(

, node); + assertHistoryMatches([{ instanceID: inst._debugID, type: 'move child', @@ -674,8 +711,9 @@ describe('ReactNativeOperationHistoryDevtool', () => { ReactDOM.render(

, node); var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - ReactNativeOperationHistoryDevtool.clearHistory(); + ReactNativeOperationHistoryDevtool._preventClearing = true; ReactDOM.render(
, node); + assertHistoryMatches([{ instanceID: inst._debugID, type: 'remove child', diff --git a/src/renderers/dom/server/ReactServerRendering.js b/src/renderers/dom/server/ReactServerRendering.js index 73ce86c46045d..ee57e07438e98 100644 --- a/src/renderers/dom/server/ReactServerRendering.js +++ b/src/renderers/dom/server/ReactServerRendering.js @@ -37,6 +37,9 @@ function renderToStringImpl(element, makeStaticMarkup) { transaction = ReactServerRenderingTransaction.getPooled(makeStaticMarkup); return transaction.perform(function() { + if (__DEV__) { + ReactInstrumentation.debugTool.onBeginFlush(); + } var componentInstance = instantiateReactComponent(element); var markup = ReactReconciler.mountComponent( componentInstance, @@ -49,6 +52,7 @@ function renderToStringImpl(element, makeStaticMarkup) { ReactInstrumentation.debugTool.onUnmountComponent( componentInstance._debugID ); + ReactInstrumentation.debugTool.onEndFlush(); } if (!makeStaticMarkup) { markup = ReactMarkupChecksum.addChecksumToMarkup(markup); diff --git a/src/renderers/native/ReactNativeMount.js b/src/renderers/native/ReactNativeMount.js index 0e5c4838bbdd8..0694ec262c2b5 100644 --- a/src/renderers/native/ReactNativeMount.js +++ b/src/renderers/native/ReactNativeMount.js @@ -216,8 +216,14 @@ var ReactNativeMount = { if (!instance) { return false; } + if (__DEV__) { + ReactInstrumentation.debugTool.onBeginFlush(); + } ReactNativeMount.unmountComponentFromNode(instance, containerTag); delete ReactNativeMount._instancesByContainerID[containerTag]; + if (__DEV__) { + ReactInstrumentation.debugTool.onEndFlush(); + } return true; },