Permalink
Switch branches/tags
Find file
Fetching contributors…
Cannot retrieve contributors at this time
226 lines (205 sloc) 6.23 KB
/**
* Copyright 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ReactReconciler
*/
'use strict';
var ReactRef = require('ReactRef');
var ReactInstrumentation = require('ReactInstrumentation');
var warning = require('warning');
/**
* Helper to call ReactRef.attachRefs with this composite component, split out
* to avoid allocations in the transaction mount-ready queue.
*/
function attachRefs(transaction) {
ReactRef.attachRefs(
this,
this._currentElement,
transaction,
);
}
var ReactReconciler = {
/**
* Initializes the component, renders markup, and registers event listeners.
*
* @param {ReactComponent} internalInstance
* @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
* @param {?object} the containing host component instance
* @param {?object} info about the host container
* @return {?string} Rendered markup to be inserted into the DOM.
* @final
* @internal
*/
mountComponent: function(
internalInstance,
transaction,
hostParent,
hostContainerInfo,
context,
parentDebugID // 0 in production and for roots
) {
if (__DEV__) {
if (internalInstance._debugID !== 0) {
ReactInstrumentation.debugTool.onBeforeMountComponent(
internalInstance._debugID,
internalInstance._currentElement,
parentDebugID
);
}
}
var markup = internalInstance.mountComponent(
transaction,
hostParent,
hostContainerInfo,
context,
parentDebugID
);
if (internalInstance._currentElement &&
internalInstance._currentElement.ref != null) {
transaction.getReactMountReady().enqueue(attachRefs, internalInstance);
}
if (__DEV__) {
if (internalInstance._debugID !== 0) {
ReactInstrumentation.debugTool.onMountComponent(
internalInstance._debugID
);
}
}
return markup;
},
/**
* Returns a value that can be passed to
* ReactComponentEnvironment.replaceNodeWithMarkup.
*/
getHostNode: function(internalInstance) {
return internalInstance.getHostNode();
},
/**
* Releases any resources allocated by `mountComponent`.
*
* @final
* @internal
*/
unmountComponent: function(internalInstance, safely) {
if (__DEV__) {
if (internalInstance._debugID !== 0) {
ReactInstrumentation.debugTool.onBeforeUnmountComponent(
internalInstance._debugID
);
}
}
ReactRef.detachRefs(internalInstance, internalInstance._currentElement);
internalInstance.unmountComponent(safely);
if (__DEV__) {
if (internalInstance._debugID !== 0) {
ReactInstrumentation.debugTool.onUnmountComponent(
internalInstance._debugID
);
}
}
},
/**
* Update a component using a new element.
*
* @param {ReactComponent} internalInstance
* @param {ReactElement} nextElement
* @param {ReactReconcileTransaction} transaction
* @param {object} context
* @internal
*/
receiveComponent: function(
internalInstance, nextElement, transaction, context
) {
var prevElement = internalInstance._currentElement;
if (nextElement === prevElement &&
context === internalInstance._context
) {
// Since elements are immutable after the owner is rendered,
// we can do a cheap identity compare here to determine if this is a
// superfluous reconcile. It's possible for state to be mutable but such
// change should trigger an update of the owner which would recreate
// the element. We explicitly check for the existence of an owner since
// it's possible for an element created outside a composite to be
// deeply mutated and reused.
// TODO: Bailing out early is just a perf optimization right?
// TODO: Removing the return statement should affect correctness?
return;
}
if (__DEV__) {
if (internalInstance._debugID !== 0) {
ReactInstrumentation.debugTool.onBeforeUpdateComponent(
internalInstance._debugID,
nextElement
);
}
}
var refsChanged = ReactRef.shouldUpdateRefs(
prevElement,
nextElement
);
if (refsChanged) {
ReactRef.detachRefs(internalInstance, prevElement);
}
internalInstance.receiveComponent(nextElement, transaction, context);
if (refsChanged &&
internalInstance._currentElement &&
internalInstance._currentElement.ref != null) {
transaction.getReactMountReady().enqueue(attachRefs, internalInstance);
}
if (__DEV__) {
if (internalInstance._debugID !== 0) {
ReactInstrumentation.debugTool.onUpdateComponent(
internalInstance._debugID
);
}
}
},
/**
* Flush any dirty changes in a component.
*
* @param {ReactComponent} internalInstance
* @param {ReactReconcileTransaction} transaction
* @internal
*/
performUpdateIfNecessary: function(
internalInstance,
transaction,
updateBatchNumber
) {
if (internalInstance._updateBatchNumber !== updateBatchNumber) {
// The component's enqueued batch number should always be the current
// batch or the following one.
warning(
internalInstance._updateBatchNumber == null ||
internalInstance._updateBatchNumber === updateBatchNumber + 1,
'performUpdateIfNecessary: Unexpected batch number (current %s, ' +
'pending %s)',
updateBatchNumber,
internalInstance._updateBatchNumber
);
return;
}
if (__DEV__) {
if (internalInstance._debugID !== 0) {
ReactInstrumentation.debugTool.onBeforeUpdateComponent(
internalInstance._debugID,
internalInstance._currentElement
);
}
}
internalInstance.performUpdateIfNecessary(transaction);
if (__DEV__) {
if (internalInstance._debugID !== 0) {
ReactInstrumentation.debugTool.onUpdateComponent(
internalInstance._debugID
);
}
}
},
};
module.exports = ReactReconciler;