Delete ReactNativeStack 🎉 🎉 🎉 (#10511)
* Removed createReactNativeComponentClassStack and renamed createReactNativeComponentClassFiber => createReactNativeComponentClass * Removed findNumericNodeHandleStack and renamed findNumericNodeHandleFiber => findNumericNodeHandle * Renamed ReactNativeFiberEntry => ReactNativeEntry * Removed all references to ReactNativeFeatureFlags and RN stack * Removed severl RN modules that are no longer used * Renamed ReactNativeEntry => ReactNativeFiberEntry for now. We'll probably remove 'fiber' references later * Update build results json * Deleted snapshot * Re-add accidentally deleted test * Remove now-unnecessary hack in test * Fix lint * RN findNodeHandle no longer adds props directly to read-only owner (#10520) * Added ReactNativeMount-test snapshot for 'renders and reorders children' test
This commit is contained in:
parent
34780da5c8
commit
2fa38ac1cc
|
@ -14,12 +14,6 @@ jest.mock('ReactFeatureFlags', () => {
|
|||
disableNewFiberFeatures: true,
|
||||
});
|
||||
});
|
||||
jest.mock('ReactNativeFeatureFlags', () => {
|
||||
const flags = require.requireActual('ReactNativeFeatureFlags');
|
||||
return Object.assign({}, flags, {
|
||||
useFiber: true,
|
||||
});
|
||||
});
|
||||
|
||||
// Error logging varies between Fiber and Stack;
|
||||
// Rather than fork dozens of tests, mock the error-logging file by default.
|
||||
|
|
|
@ -8,12 +8,6 @@ jest.mock('ReactDOMFeatureFlags', () => {
|
|||
useFiber: false,
|
||||
});
|
||||
});
|
||||
jest.mock('ReactNativeFeatureFlags', () => {
|
||||
const flags = require.requireActual('ReactNativeFeatureFlags');
|
||||
return Object.assign({}, flags, {
|
||||
useFiber: false,
|
||||
});
|
||||
});
|
||||
|
||||
// Error logging varies between Fiber and Stack;
|
||||
// Rather than fork dozens of tests, mock the error-logging file by default.
|
||||
|
|
|
@ -251,48 +251,6 @@ const bundles = [
|
|||
},
|
||||
|
||||
/******* React Native *******/
|
||||
{
|
||||
babelOpts: babelOptsReact,
|
||||
bundleTypes: [RN_DEV, RN_PROD],
|
||||
config: {
|
||||
destDir: 'build/',
|
||||
moduleName: 'ReactNativeStack',
|
||||
sourceMap: false,
|
||||
},
|
||||
entry: 'src/renderers/native/ReactNativeStackEntry',
|
||||
externals: [
|
||||
'ExceptionsManager',
|
||||
'InitializeCore',
|
||||
'ReactNativeFeatureFlags',
|
||||
'RCTEventEmitter',
|
||||
'TextInputState',
|
||||
'UIManager',
|
||||
'View',
|
||||
'deepDiffer',
|
||||
'deepFreezeAndThrowOnMutationInDev',
|
||||
'flattenStyle',
|
||||
'prop-types/checkPropTypes',
|
||||
],
|
||||
hasteName: 'ReactNativeStack',
|
||||
isRenderer: true,
|
||||
label: 'native-stack',
|
||||
manglePropertiesOnProd: false,
|
||||
name: 'react-native-renderer',
|
||||
paths: [
|
||||
'src/renderers/native/**/*.js',
|
||||
'src/renderers/shared/**/*.js',
|
||||
|
||||
'src/ReactVersion.js',
|
||||
'src/shared/**/*.js',
|
||||
],
|
||||
useFiber: false,
|
||||
modulesToStub: [
|
||||
'createReactNativeComponentClassFiber',
|
||||
'ReactNativeFiberRenderer',
|
||||
'findNumericNodeHandleFiber',
|
||||
'ReactNativeFiber',
|
||||
],
|
||||
},
|
||||
{
|
||||
babelOpts: babelOptsReact,
|
||||
bundleTypes: [RN_DEV, RN_PROD],
|
||||
|
@ -305,7 +263,6 @@ const bundles = [
|
|||
externals: [
|
||||
'ExceptionsManager',
|
||||
'InitializeCore',
|
||||
'ReactNativeFeatureFlags',
|
||||
'RCTEventEmitter',
|
||||
'TextInputState',
|
||||
'UIManager',
|
||||
|
@ -328,11 +285,6 @@ const bundles = [
|
|||
'src/shared/**/*.js',
|
||||
],
|
||||
useFiber: true,
|
||||
modulesToStub: [
|
||||
'createReactNativeComponentClassStack',
|
||||
'findNumericNodeHandleStack',
|
||||
'ReactNativeStack',
|
||||
],
|
||||
},
|
||||
|
||||
/******* React Test Renderer *******/
|
||||
|
|
|
@ -129,8 +129,6 @@ function ignoreReactNativeModules() {
|
|||
return [
|
||||
// This imports NativeMethodsMixin, causing a circular dependency.
|
||||
'View',
|
||||
// This file is injected based on a runtime config.
|
||||
'ReactNativeFeatureFlags',
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -57,24 +57,24 @@
|
|||
"gzip": 13357
|
||||
},
|
||||
"react-dom-unstable-native-dependencies.development.js (UMD_DEV)": {
|
||||
"size": 88285,
|
||||
"gzip": 22345
|
||||
"size": 87907,
|
||||
"gzip": 22195
|
||||
},
|
||||
"react-dom-unstable-native-dependencies.production.min.js (UMD_PROD)": {
|
||||
"size": 15149,
|
||||
"gzip": 4910
|
||||
},
|
||||
"react-dom-unstable-native-dependencies.development.js (NODE_DEV)": {
|
||||
"size": 81733,
|
||||
"gzip": 20383
|
||||
"size": 81355,
|
||||
"gzip": 20240
|
||||
},
|
||||
"react-dom-unstable-native-dependencies.production.min.js (NODE_PROD)": {
|
||||
"size": 13926,
|
||||
"gzip": 4403
|
||||
},
|
||||
"ReactDOMUnstableNativeDependencies-dev.js (FB_DEV)": {
|
||||
"size": 81432,
|
||||
"gzip": 20341
|
||||
"size": 81054,
|
||||
"gzip": 20200
|
||||
},
|
||||
"ReactDOMUnstableNativeDependencies-prod.js (FB_PROD)": {
|
||||
"size": 66066,
|
||||
|
@ -136,21 +136,13 @@
|
|||
"size": 220269,
|
||||
"gzip": 45845
|
||||
},
|
||||
"ReactNativeStack-dev.js (RN_DEV)": {
|
||||
"size": 201077,
|
||||
"gzip": 37401
|
||||
},
|
||||
"ReactNativeStack-prod.js (RN_PROD)": {
|
||||
"size": 136715,
|
||||
"gzip": 26222
|
||||
},
|
||||
"ReactNativeFiber-dev.js (RN_DEV)": {
|
||||
"size": 306002,
|
||||
"gzip": 52993
|
||||
"size": 303055,
|
||||
"gzip": 52683
|
||||
},
|
||||
"ReactNativeFiber-prod.js (RN_PROD)": {
|
||||
"size": 221418,
|
||||
"gzip": 38321
|
||||
"size": 218403,
|
||||
"gzip": 37966
|
||||
},
|
||||
"react-test-renderer.development.js (NODE_DEV)": {
|
||||
"size": 299567,
|
||||
|
|
|
@ -11,20 +11,14 @@
|
|||
*/
|
||||
'use strict';
|
||||
|
||||
const ReactNativeFeatureFlags = require('ReactNativeFeatureFlags');
|
||||
|
||||
import type {ReactNativeType} from 'ReactNativeTypes';
|
||||
|
||||
let ReactNative;
|
||||
|
||||
if (__DEV__) {
|
||||
ReactNative = ReactNativeFeatureFlags.useFiber
|
||||
? require('ReactNativeFiber-dev')
|
||||
: require('ReactNativeStack-dev');
|
||||
ReactNative = require('ReactNativeFiber-dev');
|
||||
} else {
|
||||
ReactNative = ReactNativeFeatureFlags.useFiber
|
||||
? require('ReactNativeFiber-prod')
|
||||
: require('ReactNativeStack-prod');
|
||||
ReactNative = require('ReactNativeFiber-prod');
|
||||
}
|
||||
|
||||
module.exports = (ReactNative: ReactNativeType);
|
||||
|
|
|
@ -6,9 +6,4 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
var ReactNativeFeatureFlags = require('ReactNativeFeatureFlags');
|
||||
var useFiber = ReactNativeFeatureFlags.useFiber;
|
||||
|
||||
module.exports = useFiber
|
||||
? require('ReactNativeFiberEntry')
|
||||
: require('ReactNativeStackEntry');
|
||||
module.exports = require('ReactNativeFiberEntry');
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -11,15 +11,15 @@
|
|||
*/
|
||||
'use strict';
|
||||
|
||||
var ReactNativeFeatureFlags = require('ReactNativeFeatureFlags');
|
||||
var ReactNativeAttributePayload = require('ReactNativeAttributePayload');
|
||||
var TextInputState = require('TextInputState');
|
||||
var UIManager = require('UIManager');
|
||||
const ReactNativeAttributePayload = require('ReactNativeAttributePayload');
|
||||
const TextInputState = require('TextInputState');
|
||||
const UIManager = require('UIManager');
|
||||
|
||||
var invariant = require('fbjs/lib/invariant');
|
||||
var findNodeHandle = require('findNodeHandle');
|
||||
const invariant = require('fbjs/lib/invariant');
|
||||
const findNodeHandle = require('findNodeHandle');
|
||||
const findNumericNodeHandle = require('findNumericNodeHandle');
|
||||
|
||||
var {
|
||||
const {
|
||||
mountSafeCallback,
|
||||
throwOnStylesProp,
|
||||
warnForStyleProps,
|
||||
|
@ -35,10 +35,6 @@ import type {
|
|||
ReactNativeBaseComponentViewConfig,
|
||||
} from 'ReactNativeViewConfigRegistry';
|
||||
|
||||
const findNumericNodeHandle = ReactNativeFeatureFlags.useFiber
|
||||
? require('findNumericNodeHandleFiber')
|
||||
: require('findNumericNodeHandleStack');
|
||||
|
||||
/**
|
||||
* `NativeMethodsMixin` provides methods to access the underlying native
|
||||
* component directly. This can be useful in cases when you want to focus
|
||||
|
@ -54,7 +50,7 @@ const findNumericNodeHandle = ReactNativeFeatureFlags.useFiber
|
|||
* Note the Flow $Exact<> syntax is required to support mixins.
|
||||
* React createClass mixins can only be used with exact types.
|
||||
*/
|
||||
var NativeMethodsMixin: $Exact<NativeMethodsMixinType> = {
|
||||
const NativeMethodsMixin: $Exact<NativeMethodsMixinType> = {
|
||||
/**
|
||||
* Determines the location on screen, width, and height of the given view and
|
||||
* returns the values via an async callback. If successful, the callback will
|
||||
|
@ -129,7 +125,49 @@ var NativeMethodsMixin: $Exact<NativeMethodsMixinType> = {
|
|||
* Manipulation](docs/direct-manipulation.html)).
|
||||
*/
|
||||
setNativeProps: function(nativeProps: Object) {
|
||||
injectedSetNativeProps(this, nativeProps);
|
||||
// Class components don't have viewConfig -> validateAttributes.
|
||||
// Nor does it make sense to set native props on a non-native component.
|
||||
// Instead, find the nearest host component and set props on it.
|
||||
// Use findNodeHandle() rather than findNumericNodeHandle() because
|
||||
// We want the instance/wrapper (not the native tag).
|
||||
let maybeInstance;
|
||||
|
||||
// Fiber errors if findNodeHandle is called for an umounted component.
|
||||
// Tests using ReactTestRenderer will trigger this case indirectly.
|
||||
// Mimicking stack behavior, we should silently ignore this case.
|
||||
// TODO Fix ReactTestRenderer so we can remove this try/catch.
|
||||
try {
|
||||
maybeInstance = findNodeHandle(this);
|
||||
} catch (error) {}
|
||||
|
||||
// If there is no host component beneath this we should fail silently.
|
||||
// This is not an error; it could mean a class component rendered null.
|
||||
if (maybeInstance == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const viewConfig: ReactNativeBaseComponentViewConfig =
|
||||
maybeInstance.viewConfig;
|
||||
|
||||
if (__DEV__) {
|
||||
warnForStyleProps(nativeProps, viewConfig.validAttributes);
|
||||
}
|
||||
|
||||
const updatePayload = ReactNativeAttributePayload.create(
|
||||
nativeProps,
|
||||
viewConfig.validAttributes,
|
||||
);
|
||||
|
||||
// Avoid the overhead of bridge calls if there's no update.
|
||||
// This is an expensive no-op for Android, and causes an unnecessary
|
||||
// view invalidation for certain components (eg RCTTextInput) on iOS.
|
||||
if (updatePayload != null) {
|
||||
UIManager.updateView(
|
||||
maybeInstance._nativeTag,
|
||||
viewConfig.uiViewClassName,
|
||||
updatePayload,
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -148,126 +186,11 @@ var NativeMethodsMixin: $Exact<NativeMethodsMixinType> = {
|
|||
},
|
||||
};
|
||||
|
||||
// TODO (bvaughn) Inline this once ReactNativeStack is dropped.
|
||||
function setNativePropsFiber(componentOrHandle: any, nativeProps: Object) {
|
||||
// Class components don't have viewConfig -> validateAttributes.
|
||||
// Nor does it make sense to set native props on a non-native component.
|
||||
// Instead, find the nearest host component and set props on it.
|
||||
// Use findNodeHandle() rather than findNumericNodeHandle() because
|
||||
// We want the instance/wrapper (not the native tag).
|
||||
let maybeInstance;
|
||||
|
||||
// Fiber errors if findNodeHandle is called for an umounted component.
|
||||
// Tests using ReactTestRenderer will trigger this case indirectly.
|
||||
// Mimicking stack behavior, we should silently ignore this case.
|
||||
// TODO Fix ReactTestRenderer so we can remove this try/catch.
|
||||
try {
|
||||
maybeInstance = findNodeHandle(componentOrHandle);
|
||||
} catch (error) {}
|
||||
|
||||
// If there is no host component beneath this we should fail silently.
|
||||
// This is not an error; it could mean a class component rendered null.
|
||||
if (maybeInstance == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const viewConfig: ReactNativeBaseComponentViewConfig =
|
||||
maybeInstance.viewConfig;
|
||||
|
||||
if (__DEV__) {
|
||||
warnForStyleProps(nativeProps, viewConfig.validAttributes);
|
||||
}
|
||||
|
||||
var updatePayload = ReactNativeAttributePayload.create(
|
||||
nativeProps,
|
||||
viewConfig.validAttributes,
|
||||
);
|
||||
|
||||
// Avoid the overhead of bridge calls if there's no update.
|
||||
// This is an expensive no-op for Android, and causes an unnecessary
|
||||
// view invalidation for certain components (eg RCTTextInput) on iOS.
|
||||
if (updatePayload != null) {
|
||||
UIManager.updateView(
|
||||
maybeInstance._nativeTag,
|
||||
viewConfig.uiViewClassName,
|
||||
updatePayload,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO (bvaughn) Remove this once ReactNativeStack is dropped.
|
||||
function setNativePropsStack(componentOrHandle: any, nativeProps: Object) {
|
||||
// Class components don't have viewConfig -> validateAttributes.
|
||||
// Nor does it make sense to set native props on a non-native component.
|
||||
// Instead, find the nearest host component and set props on it.
|
||||
// Use findNodeHandle() rather than findNumericNodeHandle() because
|
||||
// We want the instance/wrapper (not the native tag).
|
||||
let maybeInstance = findNodeHandle(componentOrHandle);
|
||||
|
||||
// If there is no host component beneath this we should fail silently.
|
||||
// This is not an error; it could mean a class component rendered null.
|
||||
if (maybeInstance == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
let viewConfig: ReactNativeBaseComponentViewConfig;
|
||||
if (maybeInstance.viewConfig !== undefined) {
|
||||
// ReactNativeBaseComponent
|
||||
viewConfig = maybeInstance.viewConfig;
|
||||
} else if (
|
||||
maybeInstance._instance !== undefined &&
|
||||
maybeInstance._instance.viewConfig !== undefined
|
||||
) {
|
||||
// ReactCompositeComponentWrapper
|
||||
// Some instances (eg Text) define their own viewConfig
|
||||
viewConfig = maybeInstance._instance.viewConfig;
|
||||
} else {
|
||||
// ReactCompositeComponentWrapper
|
||||
// Other instances (eg TextInput) defer to their children's viewConfig
|
||||
while (maybeInstance._renderedComponent !== undefined) {
|
||||
maybeInstance = maybeInstance._renderedComponent;
|
||||
}
|
||||
viewConfig = maybeInstance.viewConfig;
|
||||
}
|
||||
|
||||
const tag: number = typeof maybeInstance.getHostNode === 'function'
|
||||
? maybeInstance.getHostNode()
|
||||
: maybeInstance._rootNodeID;
|
||||
|
||||
if (__DEV__) {
|
||||
warnForStyleProps(nativeProps, viewConfig.validAttributes);
|
||||
}
|
||||
|
||||
var updatePayload = ReactNativeAttributePayload.create(
|
||||
nativeProps,
|
||||
viewConfig.validAttributes,
|
||||
);
|
||||
|
||||
if (updatePayload) {
|
||||
UIManager.updateView(tag, viewConfig.uiViewClassName, updatePayload);
|
||||
}
|
||||
}
|
||||
|
||||
// Switching based on fiber vs stack to avoid a lot of inline checks at runtime.
|
||||
// HACK Normally this injection would be done by the renderer, but in this case
|
||||
// that would result in a cycle between ReactNative and NativeMethodsMixin.
|
||||
// We avoid requiring additional code for this injection so it's probably ok?
|
||||
// TODO (bvaughn) Remove this once ReactNativeStack is gone.
|
||||
let injectedSetNativeProps: (
|
||||
componentOrHandle: any,
|
||||
nativeProps: Object,
|
||||
) => void;
|
||||
if (ReactNativeFeatureFlags.useFiber) {
|
||||
injectedSetNativeProps = setNativePropsFiber;
|
||||
} else {
|
||||
injectedSetNativeProps = setNativePropsStack;
|
||||
}
|
||||
|
||||
if (__DEV__) {
|
||||
// hide this from Flow since we can't define these properties outside of
|
||||
// __DEV__ without actually implementing them (setting them to undefined
|
||||
// isn't allowed by ReactClass)
|
||||
var NativeMethodsMixin_DEV = (NativeMethodsMixin: any);
|
||||
const NativeMethodsMixin_DEV = (NativeMethodsMixin: any);
|
||||
invariant(
|
||||
!NativeMethodsMixin_DEV.componentWillMount &&
|
||||
!NativeMethodsMixin_DEV.componentWillReceiveProps,
|
||||
|
|
|
@ -1,198 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2015-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 ReactNativeBaseComponent
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var NativeMethodsMixin = require('NativeMethodsMixin');
|
||||
var ReactNativeAttributePayload = require('ReactNativeAttributePayload');
|
||||
var ReactNativeComponentTree = require('ReactNativeComponentTree');
|
||||
var ReactNativeTagHandles = require('ReactNativeTagHandles');
|
||||
var ReactMultiChild = require('ReactMultiChild');
|
||||
var UIManager = require('UIManager');
|
||||
|
||||
var deepFreezeAndThrowOnMutationInDev = require('deepFreezeAndThrowOnMutationInDev');
|
||||
|
||||
type ReactNativeBaseComponentViewConfig = {
|
||||
validAttributes: Object,
|
||||
uiViewClassName: string,
|
||||
};
|
||||
|
||||
// require('UIManagerStatTracker').install(); // uncomment to enable
|
||||
|
||||
/**
|
||||
* @constructor ReactNativeBaseComponent
|
||||
* @extends ReactComponent
|
||||
* @extends ReactMultiChild
|
||||
* @param {!object} UIKit View Configuration.
|
||||
*/
|
||||
var ReactNativeBaseComponent = function(
|
||||
viewConfig: ReactNativeBaseComponentViewConfig,
|
||||
) {
|
||||
this.viewConfig = viewConfig;
|
||||
};
|
||||
|
||||
/**
|
||||
* Mixin for containers that contain UIViews. NOTE: markup is rendered markup
|
||||
* which is a `viewID` ... see the return value for `mountComponent` !
|
||||
*/
|
||||
ReactNativeBaseComponent.Mixin = {
|
||||
getPublicInstance: function() {
|
||||
// TODO: This should probably use a composite wrapper
|
||||
return this;
|
||||
},
|
||||
|
||||
unmountComponent: function(safely, skipLifecycle) {
|
||||
ReactNativeComponentTree.uncacheNode(this);
|
||||
this.unmountChildren(safely, skipLifecycle);
|
||||
this._rootNodeID = 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* Every native component is responsible for allocating its own `tag`, and
|
||||
* issuing the native `createView` command. But it is not responsible for
|
||||
* recording the fact that its own `rootNodeID` is associated with a
|
||||
* `nodeHandle`. Only the code that actually adds its `nodeHandle` (`tag`) as
|
||||
* a child of a container can confidently record that in
|
||||
* `ReactNativeTagHandles`.
|
||||
*/
|
||||
initializeChildren: function(children, containerTag, transaction, context) {
|
||||
var mountImages = this.mountChildren(children, transaction, context);
|
||||
// In a well balanced tree, half of the nodes are in the bottom row and have
|
||||
// no children - let's avoid calling out to the native bridge for a large
|
||||
// portion of the children.
|
||||
if (mountImages.length) {
|
||||
// TODO: Pool these per platform view class. Reusing the `mountImages`
|
||||
// array would likely be a jit deopt.
|
||||
var createdTags = [];
|
||||
for (var i = 0, l = mountImages.length; i < l; i++) {
|
||||
var mountImage = mountImages[i];
|
||||
var childTag = mountImage;
|
||||
createdTags[i] = childTag;
|
||||
}
|
||||
UIManager.setChildren(containerTag, createdTags);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the component's currently mounted representation.
|
||||
*
|
||||
* @param {object} nextElement
|
||||
* @param {ReactReconcileTransaction} transaction
|
||||
* @param {object} context
|
||||
* @internal
|
||||
*/
|
||||
receiveComponent: function(nextElement, transaction, context) {
|
||||
var prevElement = this._currentElement;
|
||||
this._currentElement = nextElement;
|
||||
|
||||
if (__DEV__) {
|
||||
for (var key in this.viewConfig.validAttributes) {
|
||||
if (nextElement.props.hasOwnProperty(key)) {
|
||||
deepFreezeAndThrowOnMutationInDev(nextElement.props[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var updatePayload = ReactNativeAttributePayload.diff(
|
||||
prevElement.props,
|
||||
nextElement.props,
|
||||
this.viewConfig.validAttributes,
|
||||
);
|
||||
|
||||
if (updatePayload) {
|
||||
UIManager.updateView(
|
||||
this._rootNodeID,
|
||||
this.viewConfig.uiViewClassName,
|
||||
updatePayload,
|
||||
);
|
||||
}
|
||||
|
||||
this.updateChildren(nextElement.props.children, transaction, context);
|
||||
},
|
||||
|
||||
getName() {
|
||||
return this.constructor.displayName || this.constructor.name || 'Unknown';
|
||||
},
|
||||
|
||||
/**
|
||||
* Currently this still uses IDs for reconciliation so this can return null.
|
||||
*
|
||||
* @return {null} Null.
|
||||
*/
|
||||
getHostNode: function() {
|
||||
return this._rootNodeID;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {ReactNativeReconcileTransaction} transaction
|
||||
* @param {?ReactNativeBaseComponent} the parent component instance
|
||||
* @param {?object} info about the host container
|
||||
* @param {object} context
|
||||
* @return {string} Unique iOS view tag.
|
||||
*/
|
||||
mountComponent: function(
|
||||
transaction,
|
||||
hostParent,
|
||||
hostContainerInfo,
|
||||
context,
|
||||
) {
|
||||
var tag = ReactNativeTagHandles.allocateTag();
|
||||
|
||||
this._rootNodeID = tag;
|
||||
this._hostParent = hostParent;
|
||||
this._hostContainerInfo = hostContainerInfo;
|
||||
|
||||
if (__DEV__) {
|
||||
for (var key in this.viewConfig.validAttributes) {
|
||||
if (this._currentElement.props.hasOwnProperty(key)) {
|
||||
deepFreezeAndThrowOnMutationInDev(this._currentElement.props[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var updatePayload = ReactNativeAttributePayload.create(
|
||||
this._currentElement.props,
|
||||
this.viewConfig.validAttributes,
|
||||
);
|
||||
|
||||
var nativeTopRootTag = hostContainerInfo._tag;
|
||||
UIManager.createView(
|
||||
tag,
|
||||
this.viewConfig.uiViewClassName,
|
||||
nativeTopRootTag,
|
||||
updatePayload,
|
||||
);
|
||||
|
||||
ReactNativeComponentTree.precacheNode(this, tag);
|
||||
|
||||
this.initializeChildren(
|
||||
this._currentElement.props.children,
|
||||
tag,
|
||||
transaction,
|
||||
context,
|
||||
);
|
||||
return tag;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Order of mixins is important. ReactNativeBaseComponent overrides methods in
|
||||
* ReactMultiChild.
|
||||
*/
|
||||
Object.assign(
|
||||
ReactNativeBaseComponent.prototype,
|
||||
ReactMultiChild,
|
||||
ReactNativeBaseComponent.Mixin,
|
||||
NativeMethodsMixin,
|
||||
);
|
||||
|
||||
module.exports = ReactNativeBaseComponent;
|
|
@ -15,11 +15,11 @@
|
|||
|
||||
const React = require('react');
|
||||
const ReactNativeAttributePayload = require('ReactNativeAttributePayload');
|
||||
const ReactNativeFeatureFlags = require('ReactNativeFeatureFlags');
|
||||
const TextInputState = require('TextInputState');
|
||||
const UIManager = require('UIManager');
|
||||
|
||||
const findNodeHandle = require('findNodeHandle');
|
||||
const findNumericNodeHandle = require('findNumericNodeHandle');
|
||||
|
||||
const {mountSafeCallback} = require('NativeMethodsMixinUtils');
|
||||
|
||||
|
@ -33,10 +33,6 @@ import type {
|
|||
ReactNativeBaseComponentViewConfig,
|
||||
} from 'ReactNativeViewConfigRegistry';
|
||||
|
||||
const findNumericNodeHandle = ReactNativeFeatureFlags.useFiber
|
||||
? require('findNumericNodeHandleFiber')
|
||||
: require('findNumericNodeHandleStack');
|
||||
|
||||
/**
|
||||
* Superclass that provides methods to access the underlying native component.
|
||||
* This can be useful when you want to focus a view or measure its dimensions.
|
||||
|
@ -136,118 +132,49 @@ class ReactNativeComponent<DefaultProps, Props, State>
|
|||
* Manipulation](docs/direct-manipulation.html)).
|
||||
*/
|
||||
setNativeProps(nativeProps: Object): void {
|
||||
injectedSetNativeProps(this, nativeProps);
|
||||
// Class components don't have viewConfig -> validateAttributes.
|
||||
// Nor does it make sense to set native props on a non-native component.
|
||||
// Instead, find the nearest host component and set props on it.
|
||||
// Use findNodeHandle() rather than ReactNative.findNodeHandle() because
|
||||
// We want the instance/wrapper (not the native tag).
|
||||
let maybeInstance;
|
||||
|
||||
// Fiber errors if findNodeHandle is called for an umounted component.
|
||||
// Tests using ReactTestRenderer will trigger this case indirectly.
|
||||
// Mimicking stack behavior, we should silently ignore this case.
|
||||
// TODO Fix ReactTestRenderer so we can remove this try/catch.
|
||||
try {
|
||||
maybeInstance = findNodeHandle(this);
|
||||
} catch (error) {}
|
||||
|
||||
// If there is no host component beneath this we should fail silently.
|
||||
// This is not an error; it could mean a class component rendered null.
|
||||
if (maybeInstance == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const viewConfig: ReactNativeBaseComponentViewConfig =
|
||||
maybeInstance.viewConfig;
|
||||
|
||||
var updatePayload = ReactNativeAttributePayload.create(
|
||||
nativeProps,
|
||||
viewConfig.validAttributes,
|
||||
);
|
||||
|
||||
// Avoid the overhead of bridge calls if there's no update.
|
||||
// This is an expensive no-op for Android, and causes an unnecessary
|
||||
// view invalidation for certain components (eg RCTTextInput) on iOS.
|
||||
if (updatePayload != null) {
|
||||
UIManager.updateView(
|
||||
maybeInstance._nativeTag,
|
||||
viewConfig.uiViewClassName,
|
||||
updatePayload,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-expressions
|
||||
(ReactNativeComponent.prototype: NativeMethodsMixinType);
|
||||
|
||||
// TODO (bvaughn) Inline this once ReactNativeStack is dropped.
|
||||
function setNativePropsFiber(componentOrHandle: any, nativeProps: Object) {
|
||||
// Class components don't have viewConfig -> validateAttributes.
|
||||
// Nor does it make sense to set native props on a non-native component.
|
||||
// Instead, find the nearest host component and set props on it.
|
||||
// Use findNodeHandle() rather than ReactNative.findNodeHandle() because
|
||||
// We want the instance/wrapper (not the native tag).
|
||||
let maybeInstance;
|
||||
|
||||
// Fiber errors if findNodeHandle is called for an umounted component.
|
||||
// Tests using ReactTestRenderer will trigger this case indirectly.
|
||||
// Mimicking stack behavior, we should silently ignore this case.
|
||||
// TODO Fix ReactTestRenderer so we can remove this try/catch.
|
||||
try {
|
||||
maybeInstance = findNodeHandle(componentOrHandle);
|
||||
} catch (error) {}
|
||||
|
||||
// If there is no host component beneath this we should fail silently.
|
||||
// This is not an error; it could mean a class component rendered null.
|
||||
if (maybeInstance == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const viewConfig: ReactNativeBaseComponentViewConfig =
|
||||
maybeInstance.viewConfig;
|
||||
|
||||
var updatePayload = ReactNativeAttributePayload.create(
|
||||
nativeProps,
|
||||
viewConfig.validAttributes,
|
||||
);
|
||||
|
||||
// Avoid the overhead of bridge calls if there's no update.
|
||||
// This is an expensive no-op for Android, and causes an unnecessary
|
||||
// view invalidation for certain components (eg RCTTextInput) on iOS.
|
||||
if (updatePayload != null) {
|
||||
UIManager.updateView(
|
||||
maybeInstance._nativeTag,
|
||||
viewConfig.uiViewClassName,
|
||||
updatePayload,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO (bvaughn) Remove this once ReactNativeStack is dropped.
|
||||
function setNativePropsStack(componentOrHandle: any, nativeProps: Object) {
|
||||
// Class components don't have viewConfig -> validateAttributes.
|
||||
// Nor does it make sense to set native props on a non-native component.
|
||||
// Instead, find the nearest host component and set props on it.
|
||||
// Use findNodeHandle() rather than ReactNative.findNodeHandle() because
|
||||
// We want the instance/wrapper (not the native tag).
|
||||
let maybeInstance = findNodeHandle(componentOrHandle);
|
||||
|
||||
// If there is no host component beneath this we should fail silently.
|
||||
// This is not an error; it could mean a class component rendered null.
|
||||
if (maybeInstance == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
let viewConfig: ReactNativeBaseComponentViewConfig;
|
||||
if (maybeInstance.viewConfig !== undefined) {
|
||||
// ReactNativeBaseComponent
|
||||
viewConfig = maybeInstance.viewConfig;
|
||||
} else if (
|
||||
maybeInstance._instance !== undefined &&
|
||||
maybeInstance._instance.viewConfig !== undefined
|
||||
) {
|
||||
// ReactCompositeComponentWrapper
|
||||
// Some instances (eg Text) define their own viewConfig
|
||||
viewConfig = maybeInstance._instance.viewConfig;
|
||||
} else {
|
||||
// ReactCompositeComponentWrapper
|
||||
// Other instances (eg TextInput) defer to their children's viewConfig
|
||||
while (maybeInstance._renderedComponent !== undefined) {
|
||||
maybeInstance = maybeInstance._renderedComponent;
|
||||
}
|
||||
viewConfig = maybeInstance.viewConfig;
|
||||
}
|
||||
|
||||
const tag: number = typeof maybeInstance.getHostNode === 'function'
|
||||
? maybeInstance.getHostNode()
|
||||
: maybeInstance._rootNodeID;
|
||||
|
||||
var updatePayload = ReactNativeAttributePayload.create(
|
||||
nativeProps,
|
||||
viewConfig.validAttributes,
|
||||
);
|
||||
|
||||
if (updatePayload != null) {
|
||||
UIManager.updateView(tag, viewConfig.uiViewClassName, updatePayload);
|
||||
}
|
||||
}
|
||||
|
||||
// Switching based on fiber vs stack to avoid a lot of inline checks at runtime.
|
||||
// HACK Normally this injection would be done by the renderer, but in this case
|
||||
// that would result in a cycle between ReactNative and NativeMethodsMixin.
|
||||
// We avoid requiring additional code for this injection so it's probably ok?
|
||||
// TODO (bvaughn) Remove this once ReactNativeStack is gone.
|
||||
let injectedSetNativeProps: (
|
||||
componentOrHandle: any,
|
||||
nativeProps: Object,
|
||||
) => void;
|
||||
if (ReactNativeFeatureFlags.useFiber) {
|
||||
injectedSetNativeProps = setNativePropsFiber;
|
||||
} else {
|
||||
injectedSetNativeProps = setNativePropsStack;
|
||||
}
|
||||
|
||||
module.exports = ReactNativeComponent;
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2015-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 ReactNativeComponentEnvironment
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var ReactNativeDOMIDOperations = require('ReactNativeDOMIDOperations');
|
||||
var ReactNativeReconcileTransaction = require('ReactNativeReconcileTransaction');
|
||||
|
||||
var ReactNativeComponentEnvironment = {
|
||||
processChildrenUpdates: ReactNativeDOMIDOperations.dangerouslyProcessChildrenUpdates,
|
||||
|
||||
replaceNodeWithMarkup: ReactNativeDOMIDOperations.dangerouslyReplaceNodeWithMarkupByID,
|
||||
|
||||
/**
|
||||
* @param {DOMElement} Element to clear.
|
||||
*/
|
||||
clearNode: function(/*containerView*/) {},
|
||||
|
||||
ReactReconcileTransaction: ReactNativeReconcileTransaction,
|
||||
};
|
||||
|
||||
module.exports = ReactNativeComponentEnvironment;
|
|
@ -61,10 +61,7 @@ function getInstanceFromTag(tag) {
|
|||
}
|
||||
|
||||
function getTagFromInstance(inst) {
|
||||
// TODO (bvaughn) Clean up once Stack is deprecated
|
||||
var tag = typeof inst.tag !== 'number'
|
||||
? inst._rootNodeID
|
||||
: inst.stateNode._nativeTag;
|
||||
var tag = inst.stateNode._nativeTag;
|
||||
invariant(tag, 'All native instances should have a tag.');
|
||||
return tag;
|
||||
}
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2015-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 ReactNativeContainerInfo
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
function ReactNativeContainerInfo(tag: number) {
|
||||
var info = {
|
||||
_tag: tag,
|
||||
};
|
||||
return info;
|
||||
}
|
||||
|
||||
module.exports = ReactNativeContainerInfo;
|
|
@ -1,85 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2015-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 ReactNativeDOMIDOperations
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var ReactNativeComponentTree = require('ReactNativeComponentTree');
|
||||
var UIManager = require('UIManager');
|
||||
|
||||
/**
|
||||
* Updates a component's children by processing a series of updates.
|
||||
* For each of the update/create commands, the `fromIndex` refers to the index
|
||||
* that the item existed at *before* any of the updates are applied, and the
|
||||
* `toIndex` refers to the index after *all* of the updates are applied
|
||||
* (including deletes/moves). TODO: refactor so this can be shared with
|
||||
* DOMChildrenOperations.
|
||||
*
|
||||
* @param {ReactNativeBaseComponent} updates List of update configurations.
|
||||
* @param {array<string>} markup List of markup strings - in the case of React
|
||||
* IOS, the ids of new components assumed to be already created.
|
||||
*/
|
||||
var dangerouslyProcessChildrenUpdates = function(inst, childrenUpdates) {
|
||||
if (!childrenUpdates.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var containerTag = ReactNativeComponentTree.getNodeFromInstance(inst);
|
||||
|
||||
var moveFromIndices;
|
||||
var moveToIndices;
|
||||
var addChildTags;
|
||||
var addAtIndices;
|
||||
var removeAtIndices;
|
||||
|
||||
for (var i = 0; i < childrenUpdates.length; i++) {
|
||||
var update = childrenUpdates[i];
|
||||
if (update.type === 'MOVE_EXISTING') {
|
||||
(moveFromIndices || (moveFromIndices = [])).push(update.fromIndex);
|
||||
(moveToIndices || (moveToIndices = [])).push(update.toIndex);
|
||||
} else if (update.type === 'REMOVE_NODE') {
|
||||
(removeAtIndices || (removeAtIndices = [])).push(update.fromIndex);
|
||||
} else if (update.type === 'INSERT_MARKUP') {
|
||||
var mountImage = update.content;
|
||||
var tag = mountImage;
|
||||
(addAtIndices || (addAtIndices = [])).push(update.toIndex);
|
||||
(addChildTags || (addChildTags = [])).push(tag);
|
||||
}
|
||||
}
|
||||
|
||||
UIManager.manageChildren(
|
||||
containerTag,
|
||||
moveFromIndices,
|
||||
moveToIndices,
|
||||
addChildTags,
|
||||
addAtIndices,
|
||||
removeAtIndices,
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Operations used to process updates to DOM nodes. This is made injectable via
|
||||
* `ReactComponent.DOMIDOperations`.
|
||||
*/
|
||||
var ReactNativeDOMIDOperations = {
|
||||
dangerouslyProcessChildrenUpdates,
|
||||
|
||||
/**
|
||||
* Replaces a view that exists in the document with markup.
|
||||
*
|
||||
* @param {string} id ID of child to be replaced.
|
||||
* @param {string} markup Mount image to replace child with id.
|
||||
*/
|
||||
dangerouslyReplaceNodeWithMarkupByID: function(id, mountImage) {
|
||||
var oldTag = id;
|
||||
UIManager.replaceExistingNonRootView(oldTag, mountImage);
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = ReactNativeDOMIDOperations;
|
|
@ -1,19 +0,0 @@
|
|||
/**
|
||||
* 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 ReactNativeFeatureFlags
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var ReactNativeFeatureFlags = {
|
||||
useFiber: true,
|
||||
};
|
||||
|
||||
module.exports = ReactNativeFeatureFlags;
|
|
@ -22,7 +22,7 @@ const ReactNativeFiberInspector = require('ReactNativeFiberInspector');
|
|||
const ReactVersion = require('ReactVersion');
|
||||
const UIManager = require('UIManager');
|
||||
|
||||
const findNumericNodeHandle = require('findNumericNodeHandleFiber');
|
||||
const findNumericNodeHandle = require('findNumericNodeHandle');
|
||||
|
||||
const {injectInternals} = require('ReactFiberDevToolsHook');
|
||||
|
||||
|
|
|
@ -15,10 +15,7 @@ var UIManager = require('UIManager');
|
|||
var ReactNativeGlobalResponderHandler = {
|
||||
onChange: function(from, to, blockNativeResponder) {
|
||||
if (to !== null) {
|
||||
// TODO (bvaughn) Clean up once Stack is deprecated
|
||||
var tag = typeof to.tag !== 'number'
|
||||
? to._rootNodeID
|
||||
: to.stateNode._nativeTag;
|
||||
var tag = to.stateNode._nativeTag;
|
||||
UIManager.setJSResponder(tag, blockNativeResponder);
|
||||
} else {
|
||||
UIManager.clearJSResponder();
|
||||
|
|
|
@ -1,227 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2015-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 ReactNativeMount
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var React = require('react');
|
||||
var ReactInstrumentation = require('ReactInstrumentation');
|
||||
var ReactNativeContainerInfo = require('ReactNativeContainerInfo');
|
||||
var ReactNativeTagHandles = require('ReactNativeTagHandles');
|
||||
var ReactReconciler = require('ReactReconciler');
|
||||
var ReactUpdateQueue = require('ReactUpdateQueue');
|
||||
var ReactUpdates = require('ReactUpdates');
|
||||
var UIManager = require('UIManager');
|
||||
|
||||
var emptyObject = require('fbjs/lib/emptyObject');
|
||||
var instantiateReactComponent = require('instantiateReactComponent');
|
||||
var shouldUpdateReactComponent = require('shouldUpdateReactComponent');
|
||||
|
||||
/**
|
||||
* Temporary (?) hack so that we can store all top-level pending updates on
|
||||
* composites instead of having to worry about different types of components
|
||||
* here.
|
||||
*/
|
||||
var TopLevelWrapper = function() {};
|
||||
TopLevelWrapper.prototype.isReactComponent = {};
|
||||
if (__DEV__) {
|
||||
TopLevelWrapper.displayName = 'TopLevelWrapper';
|
||||
}
|
||||
TopLevelWrapper.prototype.render = function() {
|
||||
return this.props.child;
|
||||
};
|
||||
TopLevelWrapper.isReactTopLevelWrapper = true;
|
||||
|
||||
/**
|
||||
* 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} containerTag container element to mount into.
|
||||
* @param {ReactReconcileTransaction} transaction
|
||||
*/
|
||||
function mountComponentIntoNode(componentInstance, containerTag, transaction) {
|
||||
var markup = ReactReconciler.mountComponent(
|
||||
componentInstance,
|
||||
transaction,
|
||||
null,
|
||||
ReactNativeContainerInfo(containerTag),
|
||||
emptyObject,
|
||||
0 /* parentDebugID */,
|
||||
);
|
||||
componentInstance._renderedComponent._topLevelWrapper = componentInstance;
|
||||
ReactNativeMount._mountImageIntoNode(markup, containerTag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Batched mount.
|
||||
*
|
||||
* @param {ReactComponent} componentInstance The instance to mount.
|
||||
* @param {number} rootID ID of the root node.
|
||||
* @param {number} containerTag container element to mount into.
|
||||
*/
|
||||
function batchedMountComponentIntoNode(componentInstance, containerTag) {
|
||||
var transaction = ReactUpdates.ReactReconcileTransaction.getPooled();
|
||||
transaction.perform(
|
||||
mountComponentIntoNode,
|
||||
null,
|
||||
componentInstance,
|
||||
containerTag,
|
||||
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 ReactNativeMount = {
|
||||
_instancesByContainerID: {},
|
||||
|
||||
// these two functions are needed by React Devtools
|
||||
findNodeHandle: require('findNodeHandle'),
|
||||
|
||||
/**
|
||||
* @param {ReactComponent} instance Instance to render.
|
||||
* @param {containerTag} containerView Handle to native view tag
|
||||
*/
|
||||
renderComponent: function(
|
||||
nextElement: ReactElement<*>,
|
||||
containerTag: number,
|
||||
callback?: ?() => void,
|
||||
): ?ReactComponent<any, any, any> {
|
||||
var nextWrappedElement = React.createElement(TopLevelWrapper, {
|
||||
child: nextElement,
|
||||
});
|
||||
|
||||
var topRootNodeID = containerTag;
|
||||
var prevComponent = ReactNativeMount._instancesByContainerID[topRootNodeID];
|
||||
if (prevComponent) {
|
||||
var prevWrappedElement = prevComponent._currentElement;
|
||||
var prevElement = prevWrappedElement.props.child;
|
||||
if (shouldUpdateReactComponent(prevElement, nextElement)) {
|
||||
ReactUpdateQueue.enqueueElementInternal(
|
||||
prevComponent,
|
||||
nextWrappedElement,
|
||||
emptyObject,
|
||||
);
|
||||
if (callback) {
|
||||
ReactUpdateQueue.enqueueCallbackInternal(prevComponent, callback);
|
||||
}
|
||||
return prevComponent;
|
||||
} else {
|
||||
ReactNativeMount.unmountComponentAtNode(containerTag);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ReactNativeTagHandles.reactTagIsNativeTopRootID(containerTag)) {
|
||||
console.error('You cannot render into anything but a top root');
|
||||
return null;
|
||||
}
|
||||
|
||||
ReactNativeTagHandles.assertRootTag(containerTag);
|
||||
|
||||
var instance = instantiateReactComponent(nextWrappedElement, false);
|
||||
ReactNativeMount._instancesByContainerID[containerTag] = instance;
|
||||
|
||||
if (callback) {
|
||||
var nonNullCallback = callback;
|
||||
instance._pendingCallbacks = [
|
||||
function() {
|
||||
nonNullCallback.call(instance._renderedComponent.getPublicInstance());
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
// 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,
|
||||
containerTag,
|
||||
);
|
||||
var component = instance._renderedComponent.getPublicInstance();
|
||||
return component;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {View} view View tree image.
|
||||
* @param {number} containerViewID View to insert sub-view into.
|
||||
*/
|
||||
_mountImageIntoNode: function(mountImage: number, containerID: number) {
|
||||
// Since we now know that the `mountImage` has been mounted, we can
|
||||
// mark it as such.
|
||||
var childTag = mountImage;
|
||||
UIManager.setChildren(containerID, [childTag]);
|
||||
},
|
||||
|
||||
/**
|
||||
* 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: number) {
|
||||
ReactNativeMount.unmountComponentAtNode(containerTag);
|
||||
// call back into native to remove all of the subviews from this container
|
||||
UIManager.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: number): boolean {
|
||||
if (!ReactNativeTagHandles.reactTagIsNativeTopRootID(containerTag)) {
|
||||
console.error('You cannot render into anything but a top root');
|
||||
return false;
|
||||
}
|
||||
|
||||
var instance = ReactNativeMount._instancesByContainerID[containerTag];
|
||||
if (!instance) {
|
||||
return false;
|
||||
}
|
||||
if (__DEV__) {
|
||||
ReactInstrumentation.debugTool.onBeginFlush();
|
||||
}
|
||||
ReactNativeMount.unmountComponentFromNode(instance, containerTag);
|
||||
delete ReactNativeMount._instancesByContainerID[containerTag];
|
||||
if (__DEV__) {
|
||||
ReactInstrumentation.debugTool.onEndFlush();
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Unmounts a component and sends messages back to iOS to remove its subviews.
|
||||
*
|
||||
* @param {ReactComponent} instance React component instance.
|
||||
* @param {string} containerID ID of container we're removing from.
|
||||
* @final
|
||||
* @internal
|
||||
* @see {ReactNativeMount.unmountComponentAtNode}
|
||||
*/
|
||||
unmountComponentFromNode: function(
|
||||
instance: ReactComponent<any, any, any>,
|
||||
containerID: number,
|
||||
) {
|
||||
// Call back into native to remove all of the subviews from this container
|
||||
ReactReconciler.unmountComponent(instance);
|
||||
UIManager.removeSubviewsFromContainerWithID(containerID);
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = ReactNativeMount;
|
|
@ -1,132 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2015-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 ReactNativeReconcileTransaction
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var CallbackQueue = require('CallbackQueue');
|
||||
var PooledClass = require('PooledClass');
|
||||
var Transaction = require('Transaction');
|
||||
var ReactInstrumentation = require('ReactInstrumentation');
|
||||
var ReactUpdateQueue = require('ReactUpdateQueue');
|
||||
|
||||
/**
|
||||
* Provides a `CallbackQueue` queue for collecting `onDOMReady` callbacks during
|
||||
* the performing of the transaction.
|
||||
*/
|
||||
var ON_DOM_READY_QUEUEING = {
|
||||
/**
|
||||
* Initializes the internal `onDOMReady` queue.
|
||||
*/
|
||||
initialize: function() {
|
||||
this.reactMountReady.reset();
|
||||
},
|
||||
|
||||
/**
|
||||
* After DOM is flushed, invoke all registered `onDOMReady` callbacks.
|
||||
*/
|
||||
close: function() {
|
||||
this.reactMountReady.notifyAll();
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Executed within the scope of the `Transaction` instance. Consider these as
|
||||
* being member methods, but with an implied ordering while being isolated from
|
||||
* each other.
|
||||
*/
|
||||
var TRANSACTION_WRAPPERS = [ON_DOM_READY_QUEUEING];
|
||||
|
||||
if (__DEV__) {
|
||||
TRANSACTION_WRAPPERS.push({
|
||||
initialize: ReactInstrumentation.debugTool.onBeginFlush,
|
||||
close: ReactInstrumentation.debugTool.onEndFlush,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Currently:
|
||||
* - The order that these are listed in the transaction is critical:
|
||||
* - Suppresses events.
|
||||
* - Restores selection range.
|
||||
*
|
||||
* Future:
|
||||
* - Restore document/overflow scroll positions that were unintentionally
|
||||
* modified via DOM insertions above the top viewport boundary.
|
||||
* - Implement/integrate with customized constraint based layout system and keep
|
||||
* track of which dimensions must be remeasured.
|
||||
*
|
||||
* @class ReactNativeReconcileTransaction
|
||||
*/
|
||||
function ReactNativeReconcileTransaction() {
|
||||
this.reinitializeTransaction();
|
||||
this.reactMountReady = CallbackQueue.getPooled();
|
||||
}
|
||||
|
||||
var Mixin = {
|
||||
/**
|
||||
* @see Transaction
|
||||
* @abstract
|
||||
* @final
|
||||
* @return {array<object>} List of operation wrap procedures.
|
||||
* TODO: convert to array<TransactionWrapper>
|
||||
*/
|
||||
getTransactionWrappers: function() {
|
||||
return TRANSACTION_WRAPPERS;
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {object} The queue to collect `onDOMReady` callbacks with.
|
||||
* TODO: convert to ReactMountReady
|
||||
*/
|
||||
getReactMountReady: function() {
|
||||
return this.reactMountReady;
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {object} The queue to collect React async events.
|
||||
*/
|
||||
getUpdateQueue: function() {
|
||||
return ReactUpdateQueue;
|
||||
},
|
||||
|
||||
/**
|
||||
* Save current transaction state -- if the return value from this method is
|
||||
* passed to `rollback`, the transaction will be reset to that state.
|
||||
*/
|
||||
checkpoint: function() {
|
||||
// reactMountReady is the our only stateful wrapper
|
||||
return this.reactMountReady.checkpoint();
|
||||
},
|
||||
|
||||
rollback: function(checkpoint) {
|
||||
this.reactMountReady.rollback(checkpoint);
|
||||
},
|
||||
|
||||
/**
|
||||
* `PooledClass` looks for this, and will invoke this before allowing this
|
||||
* instance to be reused.
|
||||
*/
|
||||
destructor: function() {
|
||||
CallbackQueue.release(this.reactMountReady);
|
||||
this.reactMountReady = null;
|
||||
},
|
||||
};
|
||||
|
||||
Object.assign(
|
||||
ReactNativeReconcileTransaction.prototype,
|
||||
Transaction,
|
||||
ReactNativeReconcileTransaction,
|
||||
Mixin,
|
||||
);
|
||||
|
||||
PooledClass.addPoolingTo(ReactNativeReconcileTransaction);
|
||||
|
||||
module.exports = ReactNativeReconcileTransaction;
|
|
@ -1,107 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2015-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 ReactNativeStackEntry
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var ReactNativeComponentTree = require('ReactNativeComponentTree');
|
||||
var ReactNativeMount = require('ReactNativeMount');
|
||||
var ReactUpdates = require('ReactUpdates');
|
||||
var ReactNativeStackInspector = require('ReactNativeStackInspector');
|
||||
|
||||
var findNumericNodeHandle = require('findNumericNodeHandleStack');
|
||||
|
||||
import type {ReactNativeType} from 'ReactNativeTypes';
|
||||
|
||||
require('ReactNativeInjection');
|
||||
require('ReactNativeStackInjection');
|
||||
|
||||
var render = function(
|
||||
element: ReactElement<any>,
|
||||
mountInto: number,
|
||||
callback?: ?() => void,
|
||||
): ?ReactComponent<any, any, any> {
|
||||
return ReactNativeMount.renderComponent(element, mountInto, callback);
|
||||
};
|
||||
|
||||
var ReactNativeStack: ReactNativeType = {
|
||||
NativeComponent: require('ReactNativeComponent'),
|
||||
|
||||
hasReactNativeInitialized: false,
|
||||
|
||||
findNodeHandle: findNumericNodeHandle,
|
||||
|
||||
render: render,
|
||||
|
||||
unmountComponentAtNode: ReactNativeMount.unmountComponentAtNode,
|
||||
|
||||
/* eslint-disable camelcase */
|
||||
unstable_batchedUpdates: ReactUpdates.batchedUpdates,
|
||||
/* eslint-enable camelcase */
|
||||
|
||||
unmountComponentAtNodeAndRemoveContainer: ReactNativeMount.unmountComponentAtNodeAndRemoveContainer,
|
||||
|
||||
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: {
|
||||
// Used as a mixin in many createClass-based components
|
||||
NativeMethodsMixin: require('NativeMethodsMixin'),
|
||||
|
||||
// Used by react-native-github/Libraries/ components
|
||||
ReactGlobalSharedState: require('ReactGlobalSharedState'), // Systrace
|
||||
ReactNativeComponentTree: require('ReactNativeComponentTree'), // InspectorUtils, ScrollResponder
|
||||
ReactNativePropRegistry: require('ReactNativePropRegistry'), // flattenStyle, Stylesheet
|
||||
TouchHistoryMath: require('TouchHistoryMath'), // PanResponder
|
||||
createReactNativeComponentClass: require('createReactNativeComponentClass'), // eg Text
|
||||
takeSnapshot: require('takeSnapshot'), // react-native-implementation
|
||||
},
|
||||
};
|
||||
|
||||
if (__DEV__) {
|
||||
// $FlowFixMe
|
||||
Object.assign(
|
||||
ReactNativeStack.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
|
||||
{
|
||||
ReactDebugTool: require('ReactDebugTool'), // RCTRenderingPerf, Systrace
|
||||
ReactPerf: require('ReactPerf'), // ReactPerfStallHandler, RCTRenderingPerf
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// Inject the runtime into a devtools global hook regardless of browser.
|
||||
// Allows for debugging when the hook is injected on the page.
|
||||
/* globals __REACT_DEVTOOLS_GLOBAL_HOOK__ */
|
||||
if (
|
||||
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' &&
|
||||
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.inject === 'function'
|
||||
) {
|
||||
__REACT_DEVTOOLS_GLOBAL_HOOK__.inject({
|
||||
ComponentTree: {
|
||||
getClosestInstanceFromNode: function(node) {
|
||||
return ReactNativeComponentTree.getClosestInstanceFromNode(node);
|
||||
},
|
||||
getNodeFromInstance: function(inst) {
|
||||
// inst is an internal instance (but could be a composite)
|
||||
while (inst._renderedComponent) {
|
||||
inst = inst._renderedComponent;
|
||||
}
|
||||
if (inst) {
|
||||
return ReactNativeComponentTree.getNodeFromInstance(inst);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
},
|
||||
Mount: ReactNativeMount,
|
||||
Reconciler: require('ReactReconciler'),
|
||||
getInspectorDataForViewTag: ReactNativeStackInspector.getInspectorDataForViewTag,
|
||||
rendererPackageName: 'react-native',
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = ReactNativeStack;
|
|
@ -1,71 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2015-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 ReactNativeStackInjection
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Make sure essential globals are available and are patched correctly. Please don't remove this
|
||||
* line. Bundles created by react-packager `require` it before executing any application code. This
|
||||
* ensures it exists in the dependency graph and can be `require`d.
|
||||
* TODO: require this in packager, not in React #10932517
|
||||
*/
|
||||
require('InitializeCore');
|
||||
|
||||
var React = require('react');
|
||||
var ReactComponentEnvironment = require('ReactComponentEnvironment');
|
||||
var ReactDefaultBatchingStrategy = require('ReactDefaultBatchingStrategy');
|
||||
var ReactEmptyComponent = require('ReactEmptyComponent');
|
||||
var ReactGenericBatching = require('ReactGenericBatching');
|
||||
var ReactHostComponent = require('ReactHostComponent');
|
||||
var ReactNativeComponentEnvironment = require('ReactNativeComponentEnvironment');
|
||||
var ReactNativeTextComponent = require('ReactNativeTextComponent');
|
||||
var ReactSimpleEmptyComponent = require('ReactSimpleEmptyComponent');
|
||||
var ReactUpdates = require('ReactUpdates');
|
||||
|
||||
var invariant = require('fbjs/lib/invariant');
|
||||
|
||||
ReactGenericBatching.injection.injectStackBatchedUpdates(
|
||||
ReactUpdates.batchedUpdates,
|
||||
);
|
||||
|
||||
ReactUpdates.injection.injectReconcileTransaction(
|
||||
ReactNativeComponentEnvironment.ReactReconcileTransaction,
|
||||
);
|
||||
|
||||
ReactUpdates.injection.injectBatchingStrategy(ReactDefaultBatchingStrategy);
|
||||
|
||||
ReactComponentEnvironment.injection.injectEnvironment(
|
||||
ReactNativeComponentEnvironment,
|
||||
);
|
||||
|
||||
var EmptyComponent = instantiate => {
|
||||
// Can't import View at the top because it depends on React to make its composite
|
||||
var View = require('View');
|
||||
return new ReactSimpleEmptyComponent(
|
||||
React.createElement(View, {
|
||||
collapsable: true,
|
||||
style: {position: 'absolute'},
|
||||
}),
|
||||
instantiate,
|
||||
);
|
||||
};
|
||||
|
||||
ReactEmptyComponent.injection.injectEmptyComponentFactory(EmptyComponent);
|
||||
|
||||
ReactHostComponent.injection.injectTextComponentClass(ReactNativeTextComponent);
|
||||
ReactHostComponent.injection.injectGenericComponentClass(function(tag) {
|
||||
// Show a nicer error message for non-function tags
|
||||
var info = '';
|
||||
if (typeof tag === 'string' && /^[a-z]/.test(tag)) {
|
||||
info += ' Each component name should start with an uppercase letter.';
|
||||
}
|
||||
invariant(false, 'Expected a component class, got %s.%s', tag, info);
|
||||
});
|
|
@ -1,106 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2015-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 ReactNativeStackInspector
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const ReactNativeComponentTree = require('ReactNativeComponentTree');
|
||||
const getComponentName = require('getComponentName');
|
||||
const emptyObject = require('fbjs/lib/emptyObject');
|
||||
const UIManager = require('UIManager');
|
||||
const invariant = require('fbjs/lib/invariant');
|
||||
|
||||
let getInspectorDataForViewTag;
|
||||
|
||||
if (__DEV__) {
|
||||
var traverseOwnerTreeUp = function(hierarchy, instance) {
|
||||
if (instance) {
|
||||
hierarchy.unshift(instance);
|
||||
traverseOwnerTreeUp(hierarchy, instance._currentElement._owner);
|
||||
}
|
||||
};
|
||||
|
||||
var getOwnerHierarchy = function(instance) {
|
||||
var hierarchy = [];
|
||||
traverseOwnerTreeUp(hierarchy, instance);
|
||||
return hierarchy;
|
||||
};
|
||||
|
||||
var lastNotNativeInstance = function(hierarchy) {
|
||||
for (let i = hierarchy.length - 1; i > 1; i--) {
|
||||
const instance = hierarchy[i];
|
||||
if (!instance.viewConfig) {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
return hierarchy[0];
|
||||
};
|
||||
|
||||
var getHostProps = function(component) {
|
||||
const instance = component._instance;
|
||||
if (instance) {
|
||||
return instance.props || emptyObject;
|
||||
}
|
||||
return emptyObject;
|
||||
};
|
||||
|
||||
var createHierarchy = function(componentHierarchy) {
|
||||
return componentHierarchy.map(component => ({
|
||||
name: getComponentName(component),
|
||||
getInspectorData: () => ({
|
||||
measure: callback =>
|
||||
UIManager.measure(component.getHostNode(), callback),
|
||||
props: getHostProps(component),
|
||||
source: component._currentElement && component._currentElement._source,
|
||||
}),
|
||||
}));
|
||||
};
|
||||
|
||||
getInspectorDataForViewTag = function(viewTag: any): Object {
|
||||
const component = ReactNativeComponentTree.getClosestInstanceFromNode(
|
||||
viewTag,
|
||||
);
|
||||
|
||||
// Handle case where user clicks outside of ReactNative
|
||||
if (!component) {
|
||||
return {
|
||||
hierarchy: [],
|
||||
props: emptyObject,
|
||||
selection: null,
|
||||
source: null,
|
||||
};
|
||||
}
|
||||
|
||||
const componentHierarchy = getOwnerHierarchy(component);
|
||||
const instance = lastNotNativeInstance(componentHierarchy);
|
||||
const hierarchy = createHierarchy(componentHierarchy);
|
||||
const props = getHostProps(instance);
|
||||
const source = instance._currentElement && instance._currentElement._source;
|
||||
const selection = componentHierarchy.indexOf(instance);
|
||||
|
||||
return {
|
||||
hierarchy,
|
||||
props,
|
||||
selection,
|
||||
source,
|
||||
};
|
||||
};
|
||||
} else {
|
||||
getInspectorDataForViewTag = () => {
|
||||
invariant(
|
||||
false,
|
||||
'getInspectorDataForViewTag() is not available in production',
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getInspectorDataForViewTag,
|
||||
};
|
|
@ -1,79 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2015-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 ReactNativeTextComponent
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var ReactNativeComponentTree = require('ReactNativeComponentTree');
|
||||
var ReactNativeTagHandles = require('ReactNativeTagHandles');
|
||||
var UIManager = require('UIManager');
|
||||
|
||||
var invariant = require('fbjs/lib/invariant');
|
||||
|
||||
var ReactNativeTextComponent = function(text) {
|
||||
// This is really a ReactText (ReactNode), not a ReactElement
|
||||
this._currentElement = text;
|
||||
this._stringText = '' + text;
|
||||
this._hostParent = null;
|
||||
this._rootNodeID = 0;
|
||||
};
|
||||
|
||||
Object.assign(ReactNativeTextComponent.prototype, {
|
||||
mountComponent: function(
|
||||
transaction,
|
||||
hostParent,
|
||||
hostContainerInfo,
|
||||
context,
|
||||
) {
|
||||
// TODO: hostParent should have this context already. Stop abusing context.
|
||||
invariant(
|
||||
context.isInAParentText,
|
||||
'RawText "%s" must be wrapped in an explicit <Text> component.',
|
||||
this._stringText,
|
||||
);
|
||||
this._hostParent = hostParent;
|
||||
var tag = ReactNativeTagHandles.allocateTag();
|
||||
this._rootNodeID = tag;
|
||||
var nativeTopRootTag = hostContainerInfo._tag;
|
||||
UIManager.createView(tag, 'RCTRawText', nativeTopRootTag, {
|
||||
text: this._stringText,
|
||||
});
|
||||
|
||||
ReactNativeComponentTree.precacheNode(this, tag);
|
||||
|
||||
return tag;
|
||||
},
|
||||
|
||||
getHostNode: function() {
|
||||
return this._rootNodeID;
|
||||
},
|
||||
|
||||
receiveComponent: function(nextText, transaction, context) {
|
||||
if (nextText !== this._currentElement) {
|
||||
this._currentElement = nextText;
|
||||
var nextStringText = '' + nextText;
|
||||
if (nextStringText !== this._stringText) {
|
||||
this._stringText = nextStringText;
|
||||
UIManager.updateView(this._rootNodeID, 'RCTRawText', {
|
||||
text: this._stringText,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
unmountComponent: function() {
|
||||
ReactNativeComponentTree.uncacheNode(this);
|
||||
this._currentElement = null;
|
||||
this._stringText = null;
|
||||
this._rootNodeID = 0;
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = ReactNativeTextComponent;
|
|
@ -11,7 +11,6 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
var PropTypes;
|
||||
var React;
|
||||
var ReactNative;
|
||||
var createReactNativeComponentClass;
|
||||
|
@ -21,7 +20,6 @@ describe('ReactNative', () => {
|
|||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
|
||||
PropTypes = require('prop-types');
|
||||
React = require('react');
|
||||
ReactNative = require('react-native');
|
||||
UIManager = require('UIManager');
|
||||
|
@ -68,35 +66,23 @@ describe('ReactNative', () => {
|
|||
uiViewClassName: 'Text',
|
||||
});
|
||||
|
||||
// Context hack is required for RN text rendering in stack.
|
||||
// TODO Remove this from the test when RN stack has been deleted.
|
||||
class Hack extends React.Component {
|
||||
static childContextTypes = {isInAParentText: PropTypes.bool};
|
||||
getChildContext() {
|
||||
return {isInAParentText: true};
|
||||
}
|
||||
render() {
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
||||
|
||||
ReactNative.render(<Hack><Text foo="a">1</Text></Hack>, 11);
|
||||
ReactNative.render(<Text foo="a">1</Text>, 11);
|
||||
expect(UIManager.updateView).not.toBeCalled();
|
||||
|
||||
// If no properties have changed, we shouldn't call updateView.
|
||||
ReactNative.render(<Hack><Text foo="a">1</Text></Hack>, 11);
|
||||
ReactNative.render(<Text foo="a">1</Text>, 11);
|
||||
expect(UIManager.updateView).not.toBeCalled();
|
||||
|
||||
// Only call updateView for the changed property (and not for text).
|
||||
ReactNative.render(<Hack><Text foo="b">1</Text></Hack>, 11);
|
||||
ReactNative.render(<Text foo="b">1</Text>, 11);
|
||||
expect(UIManager.updateView.mock.calls.length).toBe(1);
|
||||
|
||||
// Only call updateView for the changed text (and no other properties).
|
||||
ReactNative.render(<Hack><Text foo="b">2</Text></Hack>, 11);
|
||||
ReactNative.render(<Text foo="b">2</Text>, 11);
|
||||
expect(UIManager.updateView.mock.calls.length).toBe(2);
|
||||
|
||||
// Call updateView for both changed text and properties.
|
||||
ReactNative.render(<Hack><Text foo="c">3</Text></Hack>, 11);
|
||||
ReactNative.render(<Text foo="c">3</Text>, 11);
|
||||
expect(UIManager.updateView.mock.calls.length).toBe(4);
|
||||
});
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
let createReactNativeComponentClass;
|
||||
let React;
|
||||
let ReactNative;
|
||||
let ReactNativeFeatureFlags = require('ReactNativeFeatureFlags');
|
||||
|
||||
describe('createReactNativeComponentClass', () => {
|
||||
beforeEach(() => {
|
||||
|
@ -44,22 +43,20 @@ describe('createReactNativeComponentClass', () => {
|
|||
ReactNative.render(<View />, 1);
|
||||
});
|
||||
|
||||
if (ReactNativeFeatureFlags.useFiber) {
|
||||
it('should not allow viewConfigs with duplicate uiViewClassNames to be registered', () => {
|
||||
const textViewConfig = {
|
||||
validAttributes: {},
|
||||
uiViewClassName: 'Text',
|
||||
};
|
||||
const altTextViewConfig = {
|
||||
validAttributes: {},
|
||||
uiViewClassName: 'Text', // Same
|
||||
};
|
||||
it('should not allow viewConfigs with duplicate uiViewClassNames to be registered', () => {
|
||||
const textViewConfig = {
|
||||
validAttributes: {},
|
||||
uiViewClassName: 'Text',
|
||||
};
|
||||
const altTextViewConfig = {
|
||||
validAttributes: {},
|
||||
uiViewClassName: 'Text', // Same
|
||||
};
|
||||
|
||||
createReactNativeComponentClass(textViewConfig);
|
||||
createReactNativeComponentClass(textViewConfig);
|
||||
|
||||
expect(() => {
|
||||
createReactNativeComponentClass(altTextViewConfig);
|
||||
}).toThrow('Tried to register two views with the same name Text');
|
||||
});
|
||||
}
|
||||
expect(() => {
|
||||
createReactNativeComponentClass(altTextViewConfig);
|
||||
}).toThrow('Tried to register two views with the same name Text');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const ReactNativeFeatureFlags = require('ReactNativeFeatureFlags');
|
||||
const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry');
|
||||
|
||||
// See also ReactNativeBaseComponent
|
||||
export type ReactNativeBaseComponentViewConfig = {
|
||||
|
@ -21,6 +21,14 @@ export type ReactNativeBaseComponentViewConfig = {
|
|||
propTypes?: Object,
|
||||
};
|
||||
|
||||
module.exports = ReactNativeFeatureFlags.useFiber
|
||||
? require('createReactNativeComponentClassFiber')
|
||||
: require('createReactNativeComponentClassStack');
|
||||
/**
|
||||
* @param {string} config iOS View configuration.
|
||||
* @private
|
||||
*/
|
||||
const createReactNativeComponentClass = function(
|
||||
viewConfig: ReactNativeBaseComponentViewConfig,
|
||||
): string {
|
||||
return ReactNativeViewConfigRegistry.register(viewConfig);
|
||||
};
|
||||
|
||||
module.exports = createReactNativeComponentClass;
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2015-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 createReactNativeComponentClassFiber
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry');
|
||||
|
||||
import type {
|
||||
ReactNativeBaseComponentViewConfig,
|
||||
} from './createReactNativeComponentClass';
|
||||
|
||||
/**
|
||||
* @param {string} config iOS View configuration.
|
||||
* @private
|
||||
*/
|
||||
const createReactNativeComponentClassFiber = function(
|
||||
viewConfig: ReactNativeBaseComponentViewConfig,
|
||||
): string {
|
||||
return ReactNativeViewConfigRegistry.register(viewConfig);
|
||||
};
|
||||
|
||||
module.exports = createReactNativeComponentClassFiber;
|
|
@ -1,45 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2015-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 createReactNativeComponentClassStack
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const ReactNativeBaseComponent = require('ReactNativeBaseComponent');
|
||||
|
||||
import type {
|
||||
ReactNativeBaseComponentViewConfig,
|
||||
} from './createReactNativeComponentClass';
|
||||
|
||||
/**
|
||||
* @param {string} config iOS View configuration.
|
||||
* @private
|
||||
*/
|
||||
const createReactNativeComponentClassStack = function(
|
||||
viewConfig: ReactNativeBaseComponentViewConfig,
|
||||
): ReactClass<any> {
|
||||
const Constructor = function(element) {
|
||||
this._currentElement = element;
|
||||
this._topLevelWrapper = null;
|
||||
this._hostParent = null;
|
||||
this._hostContainerInfo = null;
|
||||
this._rootNodeID = 0;
|
||||
this._renderedChildren = null;
|
||||
};
|
||||
Constructor.displayName = viewConfig.uiViewClassName;
|
||||
Constructor.viewConfig = viewConfig;
|
||||
Constructor.propTypes = viewConfig.propTypes;
|
||||
Constructor.prototype = new ReactNativeBaseComponent(viewConfig);
|
||||
Constructor.prototype.constructor = Constructor;
|
||||
|
||||
return ((Constructor: any): ReactClass<any>);
|
||||
};
|
||||
|
||||
module.exports = createReactNativeComponentClassStack;
|
|
@ -13,7 +13,6 @@
|
|||
'use strict';
|
||||
|
||||
var ReactInstanceMap = require('ReactInstanceMap');
|
||||
var ReactNativeFeatureFlags = require('ReactNativeFeatureFlags');
|
||||
var ReactNativeFiberRenderer = require('ReactNativeFiberRenderer');
|
||||
var {ReactCurrentOwner} = require('ReactGlobalSharedState');
|
||||
var getComponentName = require('getComponentName');
|
||||
|
@ -24,7 +23,6 @@ if (__DEV__) {
|
|||
}
|
||||
|
||||
import type {Fiber} from 'ReactFiber';
|
||||
import type {ReactInstance} from 'ReactInstanceType';
|
||||
|
||||
/**
|
||||
* ReactNative vs ReactWeb
|
||||
|
@ -56,21 +54,15 @@ import type {ReactInstance} from 'ReactInstanceType';
|
|||
* nodeHandle N/A rootNodeID tag
|
||||
*/
|
||||
|
||||
// Rollup will strip the ReactNativeFiberRenderer from the Stack build.
|
||||
const injectedFindNode = ReactNativeFeatureFlags.useFiber
|
||||
? (fiber: Fiber) => ReactNativeFiberRenderer.findHostInstance(fiber)
|
||||
: instance => instance;
|
||||
|
||||
// TODO (bvaughn) Rename the findNodeHandle module to something more descriptive
|
||||
// eg findInternalHostInstance. This will reduce the likelihood of someone
|
||||
// accidentally deep-requiring this version.
|
||||
function findNodeHandle(componentOrHandle: any): any {
|
||||
if (__DEV__) {
|
||||
// TODO: fix this unsafe cast to work with Fiber.
|
||||
var owner = ((ReactCurrentOwner.current: any): ReactInstance | null);
|
||||
if (owner !== null) {
|
||||
var owner = ReactCurrentOwner.current;
|
||||
if (owner !== null && owner.stateNode !== null) {
|
||||
warning(
|
||||
owner._warnedAboutRefsInRender,
|
||||
owner.stateNode._warnedAboutRefsInRender,
|
||||
'%s is accessing findNodeHandle inside its render(). ' +
|
||||
'render() should be a pure function of props and state. It should ' +
|
||||
'never access something that requires stale data from the previous ' +
|
||||
|
@ -79,7 +71,7 @@ function findNodeHandle(componentOrHandle: any): any {
|
|||
getComponentName(owner) || 'A component',
|
||||
);
|
||||
|
||||
owner._warnedAboutRefsInRender = true;
|
||||
owner.stateNode._warnedAboutRefsInRender = true;
|
||||
}
|
||||
}
|
||||
if (componentOrHandle == null) {
|
||||
|
@ -94,18 +86,16 @@ function findNodeHandle(componentOrHandle: any): any {
|
|||
|
||||
// TODO (balpert): Wrap iOS native components in a composite wrapper, then
|
||||
// ReactInstanceMap.get here will always succeed for mounted components
|
||||
var internalInstance = ReactInstanceMap.get(component);
|
||||
var internalInstance: Fiber = ReactInstanceMap.get(component);
|
||||
if (internalInstance) {
|
||||
return injectedFindNode(internalInstance);
|
||||
return ReactNativeFiberRenderer.findHostInstance(internalInstance);
|
||||
} else {
|
||||
if (component) {
|
||||
return component;
|
||||
} else {
|
||||
invariant(
|
||||
// Native
|
||||
(typeof component === 'object' &&
|
||||
('_rootNodeID' in component || // TODO (bvaughn) Clean up once Stack is deprecated
|
||||
'_nativeTag' in component)) ||
|
||||
(typeof component === 'object' && '_nativeTag' in component) ||
|
||||
// Composite
|
||||
(component.render != null && typeof component.render === 'function'),
|
||||
'findNodeHandle(...): Argument is not a component ' +
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* 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 findNumericNodeHandleFiber
|
||||
* @providesModule findNumericNodeHandle
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
|
@ -1,29 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2015-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 findNumericNodeHandleStack
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var findNodeHandle = require('findNodeHandle');
|
||||
|
||||
/**
|
||||
* External users of findNodeHandle() expect the host tag number return type.
|
||||
* The injected findNodeHandle() strategy returns the instance wrapper though.
|
||||
* See NativeMethodsMixin#setNativeProps for more info on why this is done.
|
||||
*/
|
||||
module.exports = function findNumericNodeHandleStack(
|
||||
componentOrHandle: any,
|
||||
): ?number {
|
||||
const nodeHandle = findNodeHandle(componentOrHandle);
|
||||
if (nodeHandle == null || typeof nodeHandle === 'number') {
|
||||
return nodeHandle;
|
||||
}
|
||||
return nodeHandle.getHostNode();
|
||||
};
|
|
@ -11,12 +11,9 @@
|
|||
*/
|
||||
'use strict';
|
||||
|
||||
const ReactNativeFeatureFlags = require('ReactNativeFeatureFlags');
|
||||
const UIManager = require('UIManager');
|
||||
|
||||
const findNumericNodeHandle = ReactNativeFeatureFlags.useFiber
|
||||
? require('findNumericNodeHandleFiber')
|
||||
: require('findNumericNodeHandleStack');
|
||||
const findNumericNodeHandle = require('findNumericNodeHandle');
|
||||
|
||||
/**
|
||||
* Capture an image of the screen, window or an individual view. The image
|
||||
|
|
Loading…
Reference in New Issue