react-native/Libraries/ReactIOS/ReactIOSMount.js

208 lines
6.4 KiB
JavaScript
Raw Normal View History

/**
* Copyright 2004-present Facebook. All Rights Reserved.
*
* @providesModule ReactIOSMount
*/
'use strict';
var RCTUIManager = require('NativeModules').UIManager;
var ReactIOSTagHandles = require('ReactIOSTagHandles');
var ReactPerf = require('ReactPerf');
var ReactReconciler = require('ReactReconciler');
var ReactUpdates = require('ReactUpdates');
var emptyObject = require('emptyObject');
var instantiateReactComponent = require('instantiateReactComponent');
var invariant = require('invariant');
var TOP_ROOT_NODE_IDS = {};
function instanceNumberToChildRootID(rootNodeID, instanceNumber) {
return rootNodeID + '[' + instanceNumber + ']';
}
/**
* Mounts this component and inserts it into the DOM.
*
* @param {ReactComponent} componentInstance The instance to mount.
* @param {number} rootID ID of the root node.
* @param {number} container container element to mount into.
* @param {ReactReconcileTransaction} transaction
*/
function mountComponentIntoNode(
componentInstance,
rootID,
container,
transaction) {
var markup = ReactReconciler.mountComponent(
componentInstance, rootID, transaction, emptyObject
);
componentInstance._isTopLevel = true;
ReactIOSMount._mountImageIntoNode(markup, container);
}
/**
* Batched mount.
*
* @param {ReactComponent} componentInstance The instance to mount.
* @param {number} rootID ID of the root node.
* @param {number} container container element to mount into.
*/
function batchedMountComponentIntoNode(
componentInstance,
rootID,
container) {
var transaction = ReactUpdates.ReactReconcileTransaction.getPooled();
transaction.perform(
mountComponentIntoNode,
null,
componentInstance,
rootID,
container,
transaction
);
ReactUpdates.ReactReconcileTransaction.release(transaction);
}
/**
* As soon as `ReactMount` is refactored to not rely on the DOM, we can share
* code between the two. For now, we'll hard code the ID logic.
*/
var ReactIOSMount = {
instanceCount: 0,
_instancesByContainerID: {},
/**
* @param {ReactComponent} instance Instance to render.
* @param {containerTag} containerView Handle to native view tag
*/
renderComponent: function(descriptor, containerTag) {
var instance = instantiateReactComponent(descriptor);
if (!ReactIOSTagHandles.reactTagIsNativeTopRootID(containerTag)) {
console.error('You cannot render into anything but a top root');
return;
}
var topRootNodeID = ReactIOSTagHandles.allocateRootNodeIDForTag(containerTag);
ReactIOSTagHandles.associateRootNodeIDWithMountedNodeHandle(
topRootNodeID,
containerTag
);
TOP_ROOT_NODE_IDS[topRootNodeID] = true;
var childRootNodeID = instanceNumberToChildRootID(
topRootNodeID,
ReactIOSMount.instanceCount++
);
ReactIOSMount._instancesByContainerID[topRootNodeID] = instance;
// The initial render is synchronous but any updates that happen during
// rendering, in componentWillMount or componentDidMount, will be batched
// according to the current batching strategy.
ReactUpdates.batchedUpdates(
batchedMountComponentIntoNode,
instance,
childRootNodeID,
topRootNodeID
);
},
/**
* @param {View} view View tree image.
* @param {number} containerViewID View to insert sub-view into.
*/
_mountImageIntoNode: ReactPerf.measure(
// FIXME(frantic): #4441289 Hack to avoid modifying react-tools
'ReactComponentBrowserEnvironment',
'mountImageIntoNode',
function(mountImage, containerID) {
// Since we now know that the `mountImage` has been mounted, we can
// mark it as such.
ReactIOSTagHandles.associateRootNodeIDWithMountedNodeHandle(
mountImage.rootNodeID,
mountImage.tag
);
var addChildTags = [mountImage.tag];
var addAtIndices = [0];
2015-03-17 10:08:46 +00:00
RCTUIManager.manageChildren(
ReactIOSTagHandles.mostRecentMountedNodeHandleForRootNodeID(containerID),
null, // moveFromIndices
null, // moveToIndices
addChildTags,
addAtIndices,
null // removeAtIndices
);
}
),
/**
* Standard unmounting of the component that is rendered into `containerID`,
* but will also execute a command to remove the actual container view
* itself. This is useful when a client is cleaning up a React tree, and also
* knows that the container will no longer be needed. When executing
* asynchronously, it's easier to just have this method be the one that calls
* for removal of the view.
*/
unmountComponentAtNodeAndRemoveContainer: function(containerTag) {
ReactIOSMount.unmountComponentAtNode(containerTag);
// call back into native to remove all of the subviews from this container
2015-03-17 10:08:46 +00:00
RCTUIManager.removeRootView(containerTag);
},
/**
* Unmount component at container ID by iterating through each child component
* that has been rendered and unmounting it. There should just be one child
* component at this time.
*/
unmountComponentAtNode: function(containerTag) {
var containerID = ReactIOSTagHandles.tagToRootNodeID[containerTag];
invariant(
TOP_ROOT_NODE_IDS[containerID],
'We only currently support removing components from the root node'
);
var instance = ReactIOSMount._instancesByContainerID[containerID];
if (!instance) {
console.error('Tried to unmount a component that does not exist');
return false;
}
ReactIOSMount.unmountComponentFromNode(instance, containerID);
delete ReactIOSMount._instancesByContainerID[containerID];
delete TOP_ROOT_NODE_IDS[containerID];
return true;
},
/**
* Unmounts a component and sends messages back to iOS to remove its subviews.
*
* @param {ReactComponent} instance React component instance.
* @param {int} containerID ID of container we're removing from.
* @final
* @internal
* @see {ReactIOSMount.unmountComponentAtNode}
*/
unmountComponentFromNode: function(instance, containerID) {
// call back into native to remove all of the subviews from this container
instance.unmountComponent();
var containerTag =
ReactIOSTagHandles.mostRecentMountedNodeHandleForRootNodeID(containerID);
2015-03-17 10:08:46 +00:00
RCTUIManager.removeSubviewsFromContainerWithID(containerTag);
},
getNode: function(id) {
return id;
}
};
ReactIOSMount.renderComponent = ReactPerf.measure(
'ReactMount',
'_renderNewRootComponent',
ReactIOSMount.renderComponent
);
module.exports = ReactIOSMount;