@samitouri / QOS-React-2 / commits / dddebd1344

Use hack to support isMounted without stateful module

This hack allow us to get rid of the stateful module ReactLifeCycle since we can infer the value of isMounted even without it. This gets rid of the try/catch which is deopting all mountComponent calls. As a next step we could deprecate isMounted completely and avoid stateful APIs. Since it can be easily simulated if you truly need it.

Sebastian Markbage committed Jun 18, 2015 at 14:10 UTC dddebd1344d08b901a92f76891494a81f8045e6c
4 files changed +12 -85
src/renderers/shared/reconciler/ReactCompositeComponent.js
+8 -17
@@ -16,7 +16,6 @@ var ReactCurrentOwner = require('ReactCurrentOwner');
16 var ReactElement = require('ReactElement');
17 var ReactElementValidator = require('ReactElementValidator');
18 var ReactInstanceMap = require('ReactInstanceMap');
19 -var ReactLifeCycle = require('ReactLifeCycle');
19 var ReactNativeComponent = require('ReactNativeComponent');
20 var ReactPerf = require('ReactPerf');
21 var ReactPropTypeLocations = require('ReactPropTypeLocations');
@@ -218,25 +217,17 @@ var ReactCompositeComponentMixin = {
217 this._pendingReplaceState = false;
218 this._pendingForceUpdate = false;
219
221 - var renderedElement;
222 -
223 - var previouslyMounting = ReactLifeCycle.currentlyMountingInstance;
224 - ReactLifeCycle.currentlyMountingInstance = this;
225 - try {
226 - if (inst.componentWillMount) {
227 - inst.componentWillMount();
228 - // When mounting, calls to `setState` by `componentWillMount` will set
229 - // `this._pendingStateQueue` without triggering a re-render.
230 - if (this._pendingStateQueue) {
231 - inst.state = this._processPendingState(inst.props, inst.context);
232 - }
220 + if (inst.componentWillMount) {
221 + inst.componentWillMount();
222 + // When mounting, calls to `setState` by `componentWillMount` will set
223 + // `this._pendingStateQueue` without triggering a re-render.
224 + if (this._pendingStateQueue) {
225 + inst.state = this._processPendingState(inst.props, inst.context);
226 }
234 -
235 - renderedElement = this._renderValidatedComponent();
236 - } finally {
237 - ReactLifeCycle.currentlyMountingInstance = previouslyMounting;
227 }
228
229 + var renderedElement = this._renderValidatedComponent();
230 +
231 this._renderedComponent = this._instantiateReactComponent(
232 renderedElement,
233 this._currentElement.type // The wrapping type
src/renderers/shared/reconciler/ReactLifeCycle.js deleted
-29
@@ -1,29 +0,0 @@
1 -/**
2 - * Copyright 2015, Facebook, Inc.
3 - * All rights reserved.
4 - *
5 - * This source code is licensed under the BSD-style license found in the
6 - * LICENSE file in the root directory of this source tree. An additional grant
7 - * of patent rights can be found in the PATENTS file in the same directory.
8 - *
9 - * @providesModule ReactLifeCycle
10 - */
11 -
12 -'use strict';
13 -
14 -/**
15 - * This module manages the bookkeeping when a component is in the process
16 - * of being mounted or being unmounted. This is used as a way to enforce
17 - * invariants (or warnings) when it is not recommended to call
18 - * setState/forceUpdate.
19 - *
20 - * currentlyMountingInstance: During the construction phase, it is not possible
21 - * to trigger an update since the instance is not fully mounted yet. However, we
22 - * currently allow this as a convenience for mutating the initial state.
23 - */
24 -
25 -var ReactLifeCycle = {
26 - currentlyMountingInstance: null,
27 -};
28 -
29 -module.exports = ReactLifeCycle;
src/renderers/shared/reconciler/ReactUpdateQueue.js
+4 -2
@@ -11,7 +11,6 @@
11
12 'use strict';
13
14 -var ReactLifeCycle = require('ReactLifeCycle');
14 var ReactCurrentOwner = require('ReactCurrentOwner');
15 var ReactElement = require('ReactElement');
16 var ReactInstanceMap = require('ReactInstanceMap');
@@ -89,7 +88,10 @@ var ReactUpdateQueue = {
88 }
89 var internalInstance = ReactInstanceMap.get(publicInstance);
90 if (internalInstance) {
92 - return internalInstance !== ReactLifeCycle.currentlyMountingInstance;
91 + // During componentWillMount and render this will still be null but after
92 + // that will always render to something. At least for now. So we can use
93 + // this hack.
94 + return !!internalInstance._renderedComponent;
95 } else {
96 return false;
97 }
src/renderers/shared/reconciler/__tests__/ReactComponentLifeCycle-test.js
-37
@@ -14,7 +14,6 @@
14 var keyMirror = require('keyMirror');
15
16 var React;
17 -var ReactLifeCycle;
17 var ReactInstanceMap;
18 var ReactTestUtils;
19
@@ -80,28 +79,6 @@ var ComponentLifeCycle = keyMirror({
79 UNMOUNTED: null,
80 });
81
83 -/**
84 - * Composite components can also be in one of these life cycles.
85 - */
86 -var CompositeComponentLifeCycle = keyMirror({
87 - /**
88 - * Mounted components have a DOM node representation and are capable of
89 - * receiving new props.
90 - */
91 - MOUNTING: null,
92 -});
93 -
94 -function getCompositeLifeCycle(instance) {
95 - var internalInstance = ReactInstanceMap.get(instance);
96 - if (!internalInstance) {
97 - return null;
98 - }
99 - if (ReactLifeCycle.currentlyMountingInstance === internalInstance) {
100 - return CompositeComponentLifeCycle.MOUNTING;
101 - }
102 - return null;
103 -}
104 -
82 function getLifeCycleState(instance) {
83 var internalInstance = ReactInstanceMap.get(instance);
84 // Once a component gets mounted, it has an internal instance, once it
@@ -123,7 +100,6 @@ describe('ReactComponentLifeCycle', function() {
100 require('mock-modules').dumpCache();
101 React = require('React');
102 ReactTestUtils = require('ReactTestUtils');
126 - ReactLifeCycle = require('ReactLifeCycle');
103 ReactInstanceMap = require('ReactInstanceMap');
104 });
105
@@ -335,8 +311,6 @@ describe('ReactComponentLifeCycle', function() {
311 this._testJournal.returnedFromGetInitialState = clone(initState);
312 this._testJournal.lifeCycleAtStartOfGetInitialState =
313 getLifeCycleState(this);
338 - this._testJournal.compositeLifeCycleAtStartOfGetInitialState =
339 - getCompositeLifeCycle(this);
314 return initState;
315 },
316
@@ -344,8 +318,6 @@ describe('ReactComponentLifeCycle', function() {
318 this._testJournal.stateAtStartOfWillMount = clone(this.state);
319 this._testJournal.lifeCycleAtStartOfWillMount =
320 getLifeCycleState(this);
347 - this._testJournal.compositeLifeCycleAtStartOfWillMount =
348 - getCompositeLifeCycle(this);
321 this.state.hasWillMountCompleted = true;
322 },
323
@@ -361,8 +333,6 @@ describe('ReactComponentLifeCycle', function() {
333 if (isInitialRender) {
334 this._testJournal.stateInInitialRender = clone(this.state);
335 this._testJournal.lifeCycleInInitialRender = getLifeCycleState(this);
364 - this._testJournal.compositeLifeCycleInInitialRender =
365 - getCompositeLifeCycle(this);
336 } else {
337 this._testJournal.stateInLaterRender = clone(this.state);
338 this._testJournal.lifeCycleInLaterRender = getLifeCycleState(this);
@@ -396,8 +366,6 @@ describe('ReactComponentLifeCycle', function() {
366 );
367 expect(instance._testJournal.lifeCycleAtStartOfGetInitialState)
368 .toBe(ComponentLifeCycle.UNMOUNTED);
399 - expect(instance._testJournal.compositeLifeCycleAtStartOfGetInitialState)
400 - .toBe(null);
369
370 // componentWillMount
371 expect(instance._testJournal.stateAtStartOfWillMount).toEqual(
@@ -405,8 +373,6 @@ describe('ReactComponentLifeCycle', function() {
373 );
374 expect(instance._testJournal.lifeCycleAtStartOfWillMount)
375 .toBe(ComponentLifeCycle.MOUNTED);
408 - expect(instance._testJournal.compositeLifeCycleAtStartOfWillMount)
409 - .toBe(CompositeComponentLifeCycle.MOUNTING);
376
377 // componentDidMount
378 expect(instance._testJournal.stateAtStartOfDidMount)
@@ -421,9 +387,6 @@ describe('ReactComponentLifeCycle', function() {
387 expect(instance._testJournal.lifeCycleInInitialRender).toBe(
388 ComponentLifeCycle.MOUNTED
389 );
424 - expect(instance._testJournal.compositeLifeCycleInInitialRender).toBe(
425 - CompositeComponentLifeCycle.MOUNTING
426 - );
390
391 expect(getLifeCycleState(instance)).toBe(ComponentLifeCycle.MOUNTED);
392