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:
Brian Vaughn 2017-08-23 15:53:55 -07:00 committed by GitHub
parent 34780da5c8
commit 2fa38ac1cc
33 changed files with 148 additions and 3586 deletions

View File

@ -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.

View File

@ -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.

View File

@ -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 *******/

View File

@ -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',
];
}

View File

@ -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,

View File

@ -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);

View File

@ -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

View File

@ -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,

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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');

View File

@ -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();

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);
});

View File

@ -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,
};

View File

@ -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;

View File

@ -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);
});

View File

@ -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');
});
});

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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 ' +

View File

@ -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';

View File

@ -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();
};

View File

@ -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