Remove experimental RT/CS renderers (#12032)

Will follow up with adding a new one.
This commit is contained in:
Sebastian Markbåge
2018-01-17 18:07:25 -08:00
committed by GitHub
parent d8d797645c
commit d3647583b3
23 changed files with 1 additions and 1207 deletions

View File

@@ -1,16 +0,0 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
'use strict';
const ReactNativeCS = require('./src/ReactNativeCS');
// TODO: decide on the top-level export form.
// This is hacky but makes it work with both Rollup and Jest.
module.exports = ReactNativeCS.default ? ReactNativeCS.default : ReactNativeCS;

View File

@@ -1,14 +0,0 @@
{
"name": "react-cs-renderer",
"version": "16.0.0",
"private": true,
"repository": "facebook/react",
"dependencies": {
"fbjs": "^0.8.16",
"object-assign": "^4.1.1",
"prop-types": "^15.6.0"
},
"peerDependencies": {
"react": "^16.0.0"
}
}

View File

@@ -1,306 +0,0 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
import type {ReactNodeList} from 'shared/ReactTypes';
import type {ReactNativeCSType} from './ReactNativeCSTypes';
// Provided by CS:
import {CSStatefulComponent} from 'CSStatefulComponent';
import ReactFiberReconciler from 'react-reconciler';
import ReactVersion from 'shared/ReactVersion';
const emptyObject = {};
type Container = {
pendingChild: null | Instance | TextInstance,
};
type InstanceProps = Props & {children: Array<Instance>};
type Instance = {
props: InstanceProps,
options: {key: string, ref: null},
data: {type: 'NATIVE', name: string},
};
type Props = Object;
type TextInstance = Instance;
// We currently don't actually return a new state. We only use state updaters to trigger a
// rerender. Therefore our state updater is the identity functions. When we later deal
// with sync scheduling and aborted renders, we will need to update the state in render.
const identityUpdater = state => state;
// We currently don't have a hook for aborting render. Will add one once it is in place
// in React Native proper.
const infiniteDeadline = {
timeRemaining: function() {
return Infinity;
},
};
const arePropsEqual = (oldProps: Props, newProps: Props): boolean => {
let key;
for (key in newProps) {
if (key === 'children') {
// Skip special case.
continue;
}
if (newProps[key] !== oldProps[key]) {
return false;
}
}
for (key in oldProps) {
if (key === 'children') {
// Skip special case.
continue;
}
if (!(key in newProps)) {
return false;
}
}
return true;
};
// React doesn't expose its full keypath. To manage lifetime of instances, we instead use IDs.
let nextComponentKey = 0;
// Callback. Currently this is global. TODO: This should be per root.
let scheduledCallback = null;
// Updater. This is the CS updater we use to trigger the update. TODO: This should be per root.
let scheduleUpdate = null;
const ReactNativeCSFiberRenderer = ReactFiberReconciler({
appendInitialChild(
parentInstance: Instance,
child: Instance | TextInstance,
): void {
if (parentInstance.props) {
parentInstance.props.children.push(child);
} else {
// CSCustom
(parentInstance: any).children.push(child);
}
},
createInstance(
type: string,
props: Props,
rootContainerInstance: Container,
hostContext: {},
internalInstanceHandle: Object,
): Instance {
let key = '' + nextComponentKey++;
let ref = null; // TODO: Always create Ref object so that getPublicInstance can use it.
// We need a new props object so that we can represent flattened children.
let newProps = Object.assign({}, props);
newProps.children = [];
if (type === 'CSCustom') {
// Special cased type that treats the props as the object.
// Useful for custom children types like FlexItem.
return newProps;
}
return {
props: newProps,
options: {key, ref},
data: {type: 'NATIVE', name: type},
};
},
createTextInstance(
text: string,
rootContainerInstance: Container,
hostContext: {},
internalInstanceHandle: Object,
): TextInstance {
// Could auto-translate to CSText with some host context defined attributes.
throw new Error('Not yet implemented.');
},
finalizeInitialChildren(
parentInstance: Instance,
type: string,
props: Props,
rootContainerInstance: Container,
): boolean {
return false;
},
getRootHostContext(): {} {
return emptyObject;
},
getChildHostContext(): {} {
return emptyObject;
},
getPublicInstance(instance: Instance) {
return instance.options.ref;
},
prepareForCommit(): void {},
prepareUpdate(
instance: Instance,
type: string,
oldProps: Props,
newProps: Props,
rootContainerInstance: Container,
hostContext: {},
): null | InstanceProps {
if (arePropsEqual(oldProps, newProps)) {
return null;
}
return Object.assign({}, newProps);
},
resetAfterCommit(): void {},
shouldDeprioritizeSubtree(type: string, props: Props): boolean {
return false;
},
scheduleDeferredCallback(callback) {
scheduledCallback = callback;
if (scheduleUpdate !== null) {
scheduleUpdate(identityUpdater);
}
return 0;
},
cancelDeferredCallback() {
// Noop. This is always called right before scheduling a new update, so
// should be fine. This renderer won't use requestIdleCallback, anyway.
// Will switch to use shouldYield() API instead.
},
shouldSetTextContent(type: string, props: Props): boolean {
// TODO: Figure out when we should allow text content.
return false;
},
now(): number {
// TODO: Enable expiration by implementing this method.
return 0;
},
persistence: {
cloneInstance(
instance: Instance,
updatePayload: null | InstanceProps,
type: string,
oldProps: Props,
newProps: Props,
internalInstanceHandle: Object,
keepChildren: boolean,
recyclableInstance: null | Instance,
): Instance {
let newInstanceProps = updatePayload;
if (newInstanceProps === null) {
newInstanceProps = Object.assign({}, newProps);
}
// We need a new props object so that we can represent flattened children.
newInstanceProps.children = keepChildren ? instance.props.children : [];
if (type === 'CSCustom') {
return newInstanceProps;
}
return {
props: newInstanceProps,
options: instance.options,
data: instance.data,
};
},
createContainerChildSet(container: Container): Container {
// We'll only ever have one instance in the container.
container.pendingChild = null;
return container;
},
appendChildToContainerChildSet(
childSet: Container,
child: Instance | TextInstance,
): void {
if (childSet.pendingChild !== null) {
throw new Error(
'CSReact does not support top level fragments. Wrap it in a primitve.',
);
}
childSet.pendingChild = child;
},
finalizeContainerChildren(
container: Container,
newChildren: Container,
): void {},
replaceContainerChildren(
container: Container,
newChildren: Container,
): void {},
},
});
ReactNativeCSFiberRenderer.injectIntoDevTools({
bundleType: __DEV__ ? 1 : 0,
version: ReactVersion,
rendererPackageName: 'react-cs-renderer',
});
type ReactCSProps = {children: ReactNodeList};
type ReactCSState = {
root: Object,
container: {
pendingChild: null | Instance | TextInstance,
},
};
const ReactCS = CSStatefulComponent({
getInitialState({props}: {props: ReactCSProps}): ReactCSState {
let container = {
pendingChild: null,
};
let root = ReactNativeCSFiberRenderer.createContainer(
container,
false,
false,
);
return {root, container};
},
render({
props,
state,
stateUpdater,
}: {
props: ReactCSProps,
state: ReactCSState,
stateUpdater: (update: (oldState: ReactCSState) => ReactCSState) => void,
}) {
scheduleUpdate = stateUpdater;
// TODO: For a props rerender updateContainer will schedule an additional state
// update even though it is not necessary since we're already rendering.
// We should only call scheduleUpdate for a React setState, not a top level
// props update.
ReactNativeCSFiberRenderer.updateContainer(
props.children,
state.root,
null,
null,
);
if (scheduledCallback) {
const callback = scheduledCallback;
scheduledCallback = null;
callback(infiniteDeadline);
}
return state.container.pendingChild;
},
getInstance({state}: {state: ReactCSState}) {
return ReactNativeCSFiberRenderer.getPublicRootInstance(state.root);
},
// TODO: Unmount hook. E.g. finalizer.
});
export default (ReactCS: ReactNativeCSType);

View File

@@ -1,29 +0,0 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @providesModule ReactNativeCSTypes
*/
/**
* Flat CS renderer bundles are too big for Flow to parse efficiently.
* Provide minimal Flow typing for the high-level API and call it a day.
*/
import type {Options, Element} from 'CSComponent';
export type Children<ChildType> = {|
+children: $ReadOnlyArray<React$Element<ChildType>>,
|};
type StatelessComponent<Props> = React$StatelessFunctionalComponent<Props>;
type ClassComponent<Props, Instance> = Class<React$Component<Props> & Instance>;
export type ReactNativeCSType = <Props, Instance>(
props: Children<ClassComponent<Props, Instance> | StatelessComponent<Props>>,
options: Options<Instance> | void,
) => Element;

View File

@@ -1,14 +0,0 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
// Mock of the CS Hooks
export const CSStatefulComponent = function(spec) {
return spec;
};

View File

@@ -1,35 +0,0 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
* @jest-environment node
*/
'use strict';
let React;
let ReactNativeCS;
jest.mock('shared/ReactFeatureFlags', () =>
require('shared/forks/ReactFeatureFlags.native-cs'),
);
describe('ReactNativeCS', () => {
beforeEach(() => {
jest.resetModules();
React = require('react');
ReactNativeCS = require('react-cs-renderer');
});
it('should be able to create and render a native component', () => {
const CSView = 'View';
const props = <CSView foo="test" />;
const state = ReactNativeCS.getInitialState({});
const stateUpdater = function() {};
ReactNativeCS.render({props, state, stateUpdater});
});
});

View File

@@ -1,26 +0,0 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
// Mock of the Native Hooks
const RCTRTManager = {
createNode: jest.fn(function createView(tag, classType, props) {}),
beginUpdates: jest.fn(function beginUpdates() {}),
appendChildToContext: jest.fn(function appendChildToContext(
contextTag,
childTag,
) {}),
appendChild: jest.fn(function appendChild(parentTag, childTag) {}),
prependChild: jest.fn(function prependChild(childTag, beforeTag) {}),
deleteChild: jest.fn(function deleteChild(childTag) {}),
updateNode: jest.fn(function updateNode(tag, props) {}),
completeUpdates: jest.fn(function completeUpdates() {}),
};
module.exports = RCTRTManager;

View File

@@ -1,14 +0,0 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
const ReactNativeRT = require('./src/ReactNativeRT');
// TODO: decide on the top-level export form.
// This is hacky but makes it work with both Rollup and Jest.
module.exports = ReactNativeRT.default ? ReactNativeRT.default : ReactNativeRT;

View File

@@ -1,14 +0,0 @@
{
"name": "react-rt-renderer",
"version": "16.0.0",
"private": true,
"repository": "facebook/react",
"dependencies": {
"fbjs": "^0.8.16",
"object-assign": "^4.1.1",
"prop-types": "^15.6.0"
},
"peerDependencies": {
"react": "^16.0.0"
}
}

View File

@@ -1,87 +0,0 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
import type {ReactNativeRTType} from './ReactNativeRTTypes';
import type {ReactNodeList} from 'shared/ReactTypes';
/**
* 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
*/
import 'InitializeCore';
import './ReactNativeRTEventEmitter';
import * as ReactPortal from 'shared/ReactPortal';
import * as ReactGenericBatching from 'events/ReactGenericBatching';
import ReactVersion from 'shared/ReactVersion';
import {getFiberFromTag} from './ReactNativeRTComponentTree';
import ReactNativeRTFiberRenderer from './ReactNativeRTFiberRenderer';
import ReactNativeRTFiberInspector from './ReactNativeRTFiberInspector';
ReactGenericBatching.injection.injectFiberBatchedUpdates(
ReactNativeRTFiberRenderer.batchedUpdates,
);
const roots = new Map();
const ReactNativeRTFiber: ReactNativeRTType = {
render(element: React$Element<any>, containerTag: any, callback: ?Function) {
let root = roots.get(containerTag);
if (!root) {
// TODO (bvaughn): If we decide to keep the wrapper component,
// We could create a wrapper for containerTag as well to reduce special casing.
root = ReactNativeRTFiberRenderer.createContainer(
containerTag,
false,
false,
);
roots.set(containerTag, root);
}
ReactNativeRTFiberRenderer.updateContainer(element, root, null, callback);
return ReactNativeRTFiberRenderer.getPublicRootInstance(root);
},
unmountComponentAtNode(containerTag: number) {
const root = roots.get(containerTag);
if (root) {
// TODO: Is it safe to reset this now or should I wait since this unmount could be deferred?
ReactNativeRTFiberRenderer.updateContainer(null, root, null, () => {
roots.delete(containerTag);
});
}
},
createPortal(
children: ReactNodeList,
containerTag: number,
key: ?string = null,
) {
return ReactPortal.createPortal(children, containerTag, null, key);
},
unstable_batchedUpdates: ReactGenericBatching.batchedUpdates,
flushSync: ReactNativeRTFiberRenderer.flushSync,
};
ReactNativeRTFiberRenderer.injectIntoDevTools({
findFiberByHostInstance: getFiberFromTag,
getInspectorDataForViewTag:
ReactNativeRTFiberInspector.getInspectorDataForViewTag,
bundleType: __DEV__ ? 1 : 0,
version: ReactVersion,
rendererPackageName: 'react-rt-renderer',
});
export default ReactNativeRTFiber;

View File

@@ -1,34 +0,0 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
import type {Fiber} from 'react-reconciler/src/ReactFiber';
const instanceCache: {[key: number]: Fiber} = {};
const instanceProps: {[key: number]: Object} = {};
export function precacheFiberNode(fiber: Fiber, tag: number): void {
instanceCache[tag] = fiber;
}
export function getFiberFromTag(tag: number): null | Fiber {
return instanceCache[tag] || null;
}
export function uncacheFiberNode(tag: number): void {
delete instanceCache[tag];
delete instanceProps[tag];
}
export function getFiberCurrentPropsFromTag(tag: number): null | Object {
return instanceProps[tag] || null;
}
export function updateFiberProps(tag: number, props: Object): void {
instanceProps[tag] = props;
}

View File

@@ -1,47 +0,0 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
import {batchedUpdates} from 'events/ReactGenericBatching';
// Module provided by RN:
import BatchedBridge from 'BatchedBridge';
import {getFiberCurrentPropsFromTag} from './ReactNativeRTComponentTree';
const ReactNativeRTEventEmitter = {
/**
* Publicly exposed method on module for native objc to invoke when a top
* level event is extracted.
* @param {rootNodeID} rootNodeID React root node ID that event occurred on.
* @param {TopLevelType} topLevelType Top level type of event.
* @param {object} nativeEventParam Object passed from native.
*/
receiveEvent: function(
tag: number,
topLevelType: string,
nativeEventParam: Object,
) {
const nativeEvent = nativeEventParam;
const props = getFiberCurrentPropsFromTag(tag);
if (props == null) {
return;
}
const eventHandler = props[topLevelType];
if (typeof eventHandler !== 'function') {
return;
}
batchedUpdates(function() {
eventHandler(nativeEvent);
});
},
};
BatchedBridge.registerCallableModule(
'RTEventEmitter',
ReactNativeRTEventEmitter,
);

View File

@@ -1,106 +0,0 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
import {
findCurrentFiberUsingSlowPath,
findCurrentHostFiber,
} from 'react-reconciler/reflection';
import getComponentName from 'shared/getComponentName';
import {HostComponent} from 'shared/ReactTypeOfWork';
import emptyObject from 'fbjs/lib/emptyObject';
import invariant from 'fbjs/lib/invariant';
import {getFiberFromTag} from './ReactNativeRTComponentTree';
let getInspectorDataForViewTag;
if (__DEV__) {
const traverseOwnerTreeUp = function(hierarchy, instance: any) {
if (instance) {
hierarchy.unshift(instance);
traverseOwnerTreeUp(hierarchy, instance._debugOwner);
}
};
const getOwnerHierarchy = function(instance: any) {
const hierarchy = [];
traverseOwnerTreeUp(hierarchy, instance);
return hierarchy;
};
const lastNonHostInstance = function(hierarchy) {
for (let i = hierarchy.length - 1; i > 1; i--) {
const instance = hierarchy[i];
if (instance.tag !== HostComponent) {
return instance;
}
}
return hierarchy[0];
};
const getHostProps = function(fiber) {
const host = findCurrentHostFiber(fiber);
if (host) {
return host.memoizedProps || emptyObject;
}
return emptyObject;
};
const createHierarchy = function(fiberHierarchy) {
return fiberHierarchy.map(fiber => ({
name: getComponentName(fiber),
getInspectorData: findNodeHandle => ({
measure: callback => invariant(false, 'Measure not implemented yet'),
props: getHostProps(fiber),
source: fiber._debugSource,
}),
}));
};
getInspectorDataForViewTag = function(viewTag: number): Object {
const closestInstance = getFiberFromTag(viewTag);
// Handle case where user clicks outside of ReactNative
if (!closestInstance) {
return {
hierarchy: [],
props: emptyObject,
selection: null,
source: null,
};
}
const fiber = findCurrentFiberUsingSlowPath(closestInstance);
const fiberHierarchy = getOwnerHierarchy(fiber);
const instance = lastNonHostInstance(fiberHierarchy);
const hierarchy = createHierarchy(fiberHierarchy);
const props = getHostProps(instance);
const source = instance._debugSource;
const selection = fiberHierarchy.indexOf(instance);
return {
hierarchy,
props,
selection,
source,
};
};
} else {
getInspectorDataForViewTag = () => {
invariant(
false,
'getInspectorDataForViewTag() is not available in production',
);
};
}
export default {
getInspectorDataForViewTag,
};

View File

@@ -1,243 +0,0 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
import ReactFiberReconciler from 'react-reconciler';
import emptyObject from 'fbjs/lib/emptyObject';
import invariant from 'fbjs/lib/invariant';
// Module provided by RN:
import RTManager from 'RTManager';
import {
precacheFiberNode,
updateFiberProps,
} from './ReactNativeRTComponentTree';
import ReactNativeRTTagHandles from './ReactNativeRTTagHandles';
export type Container = number;
export type Instance = number;
export type Props = Object;
export type TextInstance = number;
function processProps(instance: number, props: Props): Object {
const propsPayload = {};
for (const key in props) {
if (key === 'children') {
// Skip special case.
continue;
}
let value = props[key];
if (typeof value === 'function') {
value = {
style: 'rt-event',
event: key,
tag: instance,
};
}
propsPayload[key] = value;
}
return propsPayload;
}
function arePropsEqual(oldProps: Props, newProps: Props): boolean {
let key;
for (key in newProps) {
if (key === 'children') {
// Skip special case.
continue;
}
if (newProps[key] !== oldProps[key]) {
return false;
}
}
for (key in oldProps) {
if (key === 'children') {
// Skip special case.
continue;
}
if (!(key in newProps)) {
return false;
}
}
return true;
}
const NativeRTRenderer = ReactFiberReconciler({
appendInitialChild(
parentInstance: Instance,
child: Instance | TextInstance,
): void {
RTManager.appendChild(parentInstance, child);
},
createInstance(
type: string,
props: Props,
rootContainerInstance: Container,
hostContext: {},
internalInstanceHandle: Object,
): Instance {
const tag = ReactNativeRTTagHandles.allocateTag();
precacheFiberNode(internalInstanceHandle, tag);
updateFiberProps(tag, props);
RTManager.createNode(tag, type, processProps(tag, props));
return tag;
},
createTextInstance(
text: string,
rootContainerInstance: Container,
hostContext: {},
internalInstanceHandle: Object,
): TextInstance {
invariant(false, 'Text components are not supported for now.');
},
finalizeInitialChildren(
parentInstance: Instance,
type: string,
props: Props,
rootContainerInstance: Container,
): boolean {
return false;
},
getRootHostContext(): {} {
return emptyObject;
},
getChildHostContext(): {} {
return emptyObject;
},
getPublicInstance(instance) {
return instance;
},
prepareForCommit(): void {
RTManager.beginUpdates();
},
prepareUpdate(
instance: Instance,
type: string,
oldProps: Props,
newProps: Props,
rootContainerInstance: Container,
hostContext: {},
): null | Object {
if (arePropsEqual(oldProps, newProps)) {
return null;
}
return processProps(instance, newProps);
},
resetAfterCommit(): void {
RTManager.completeUpdates();
},
shouldDeprioritizeSubtree(type: string, props: Props): boolean {
return false;
},
scheduleDeferredCallback: global.requestIdleCallback,
cancelDeferredCallback: global.cancelIdleCallback,
shouldSetTextContent(type: string, props: Props): boolean {
// TODO: Figure out when we should allow text content.
return false;
},
now(): number {
// TODO: Enable expiration by implementing this method.
return 0;
},
mutation: {
appendChild(
parentInstance: Instance,
child: Instance | TextInstance,
): void {
RTManager.appendChild(parentInstance, child);
},
appendChildToContainer(
parentInstance: Container,
child: Instance | TextInstance,
): void {
RTManager.appendChildToContext(parentInstance, child);
},
commitTextUpdate(
textInstance: TextInstance,
oldText: string,
newText: string,
): void {
invariant(false, 'Text components are not yet supported.');
},
commitMount(
instance: Instance,
type: string,
newProps: Props,
internalInstanceHandle: Object,
): void {
// Noop
},
commitUpdate(
instance: Instance,
updatePayload: Object,
type: string,
oldProps: Props,
newProps: Props,
internalInstanceHandle: Object,
): void {
updateFiberProps(instance, newProps);
RTManager.updateNode(instance, updatePayload);
},
insertBefore(
parentInstance: Instance,
child: Instance | TextInstance,
beforeChild: Instance | TextInstance,
): void {
RTManager.prependChild(child, beforeChild);
},
insertInContainerBefore(
parentInstance: Container,
child: Instance | TextInstance,
beforeChild: Instance | TextInstance,
): void {
RTManager.prependChild(child, beforeChild);
},
removeChild(
parentInstance: Instance,
child: Instance | TextInstance,
): void {
// TODO: recursively uncache, by traversing fibers, this will currently leak
RTManager.deleteChild(child);
},
removeChildFromContainer(
parentInstance: Container,
child: Instance | TextInstance,
): void {
// TODO: recursively uncache, by traversing fibers, this will currently leak
RTManager.deleteChild(child);
},
resetTextContent(instance: Instance): void {
// Noop
},
},
});
export default NativeRTRenderer;

View File

@@ -1,51 +0,0 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
import invariant from 'fbjs/lib/invariant';
/**
* Keeps track of allocating and associating native "tags" which are numeric,
* unique view IDs. All the native tags are negative numbers, to avoid
* collisions, but in the JS we keep track of them as positive integers to store
* them effectively in Arrays. So we must refer to them as "inverses" of the
* native tags (that are * normally negative).
*
* It *must* be the case that every `rootNodeID` always maps to the exact same
* `tag` forever. The easiest way to accomplish this is to never delete
* anything from this table.
* Why: Because `dangerouslyReplaceNodeWithMarkupByID` relies on being able to
* unmount a component with a `rootNodeID`, then mount a new one in its place,
*/
const INITIAL_TAG_COUNT = 1;
const ReactNativeRTTagHandles = {
tagsStartAt: INITIAL_TAG_COUNT,
tagCount: INITIAL_TAG_COUNT,
allocateTag: function(): number {
// Skip over root IDs as those are reserved for native
const tag = ReactNativeRTTagHandles.tagCount;
ReactNativeRTTagHandles.tagCount++;
return tag;
},
assertRootTag: function(tag: number): void {
invariant(
ReactNativeRTTagHandles.reactTagIsNativeID(tag),
'Expect a native root tag, instead got %s',
tag,
);
},
reactTagIsNativeID: function(reactTag: number): boolean {
// We reserve all tags that are 1 mod 10 for native view creation
return reactTag % 10 === 1;
},
};
export default ReactNativeRTTagHandles;

View File

@@ -1,23 +0,0 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @providesModule ReactNativeRTTypes
*/
/**
* Flat RT renderer bundles are too big for Flow to parse efficiently.
* Provide minimal Flow typing for the high-level RN API and call it a day.
*/
export type ReactNativeRTType = {
render(
element: React$Element<any>,
containerTag: any,
callback: ?Function,
): any,
unmountComponentAtNode(containerTag: number): any,
unstable_batchedUpdates: any, // TODO (bvaughn) Add types
};

View File

@@ -1,62 +0,0 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
* @jest-environment node
*/
'use strict';
let React;
let ReactNativeRT;
let RTManager;
describe('ReactNativeRT', () => {
beforeEach(() => {
jest.resetModules();
React = require('react');
ReactNativeRT = require('react-rt-renderer');
RTManager = require('RTManager');
});
it('should be able to create and render a native component', () => {
ReactNativeRT.render(<rt-box foo="test" />, 1);
expect(RTManager.createNode).toBeCalled();
expect(RTManager.appendChildToContext).toBeCalled();
expect(RTManager.appendChild).not.toBeCalled();
expect(RTManager.updateNode).not.toBeCalled();
});
it('should be able to create and update a native component', () => {
ReactNativeRT.render(<rt-box foo="foo" />, 11);
expect(RTManager.createNode.mock.calls.length).toBe(1);
expect(RTManager.createNode).toBeCalledWith(1, 'rt-box', {foo: 'foo'});
expect(RTManager.appendChildToContext.mock.calls.length).toBe(1);
expect(RTManager.appendChild).not.toBeCalled();
expect(RTManager.updateNode).not.toBeCalled();
ReactNativeRT.render(<rt-box foo="bar" />, 11);
expect(RTManager.createNode.mock.calls.length).toBe(1);
expect(RTManager.appendChildToContext.mock.calls.length).toBe(1);
expect(RTManager.appendChild).not.toBeCalled();
expect(RTManager.updateNode).toBeCalledWith(1, {foo: 'bar'});
ReactNativeRT.render(
<rt-box foo="bar">
<rt-box />
</rt-box>,
11,
);
expect(RTManager.createNode.mock.calls.length).toBe(2);
expect(RTManager.appendChildToContext.mock.calls.length).toBe(1);
expect(RTManager.appendChildToContext.mock.calls.length).toBe(1);
expect(RTManager.updateNode.mock.calls.length).toBe(1);
});
});

View File

@@ -3,9 +3,7 @@
set -e
# Make sure we don't introduce accidental @providesModule annotations.
EXPECTED='packages/react-cs-renderer/src/ReactNativeCSTypes.js
packages/react-native-renderer/src/ReactNativeTypes.js
packages/react-rt-renderer/src/ReactNativeRTTypes.js
EXPECTED='packages/react-native-renderer/src/ReactNativeTypes.js
packages/shared/ReactTypes.js
scripts/rollup/wrappers.js'
ACTUAL=$(git grep -l @providesModule -- './*.js' ':!scripts/rollup/shims/*.js')

View File

@@ -131,32 +131,6 @@ const bundles = [
],
},
/******* React Native RT *******/
{
label: 'native-rt',
bundleTypes: [RN_DEV, RN_PROD],
moduleType: RENDERER,
entry: 'react-rt-renderer',
global: 'ReactRTRenderer',
externals: [
'ExceptionsManager',
'InitializeCore',
'Platform',
'BatchedBridge',
'RTManager',
],
},
/******* React Native CS *******/
{
label: 'native-cs',
bundleTypes: [RN_DEV, RN_PROD],
moduleType: RENDERER,
entry: 'react-cs-renderer',
global: 'ReactCSRenderer',
externals: ['CSStatefulComponent'],
},
/******* React Test Renderer *******/
{
label: 'test',

View File

@@ -34,8 +34,6 @@ const forks = Object.freeze({
switch (entry) {
case 'react-native-renderer':
return 'shared/forks/ReactFeatureFlags.native.js';
case 'react-cs-renderer':
return 'shared/forks/ReactFeatureFlags.native-cs.js';
default:
switch (bundleType) {
case FB_DEV:
@@ -91,7 +89,6 @@ const forks = Object.freeze({
case RN_PROD:
switch (entry) {
case 'react-native-renderer':
case 'react-rt-renderer':
// Use the RN fork which plays well with redbox.
return 'react-reconciler/src/forks/ReactFiberErrorDialog.native.js';
default:

View File

@@ -44,10 +44,6 @@ function getBundleOutputPaths(bundleType, filename, packageName) {
case RN_DEV:
case RN_PROD:
switch (packageName) {
case 'react-rt-renderer':
return [`build/react-rt/${filename}`];
case 'react-cs-renderer':
return [`build/react-cs/${filename}`];
case 'react-native-renderer':
return [`build/react-native/${filename}`];
default:
@@ -77,16 +73,6 @@ async function copyRNShims() {
require.resolve('react-native-renderer/src/ReactNativeTypes.js'),
'build/react-native/shims/ReactNativeTypes.js'
),
// React Native CS
asyncCopyTo(
require.resolve('react-cs-renderer/src/ReactNativeCSTypes.js'),
'build/react-cs/shims/ReactNativeCSTypes.js'
),
// React Native RT
asyncCopyTo(
require.resolve('react-rt-renderer/src/ReactNativeRTTypes.js'),
'build/react-rt/shims/ReactNativeRTTypes.js'
),
]);
}

View File

@@ -273,34 +273,6 @@
"size": 196483,
"gzip": 34394
},
{
"filename": "ReactRTRenderer-dev.js",
"bundleType": "RN_DEV",
"packageName": "react-rt-renderer",
"size": 286506,
"gzip": 61843
},
{
"filename": "ReactRTRenderer-prod.js",
"bundleType": "RN_PROD",
"packageName": "react-rt-renderer",
"size": 133702,
"gzip": 23039
},
{
"filename": "ReactCSRenderer-dev.js",
"bundleType": "RN_DEV",
"packageName": "react-cs-renderer",
"size": 277130,
"gzip": 58953
},
{
"filename": "ReactCSRenderer-prod.js",
"bundleType": "RN_PROD",
"packageName": "react-cs-renderer",
"size": 126142,
"gzip": 21682
},
{
"filename": "react-test-renderer.development.js",
"bundleType": "NODE_DEV",

View File

@@ -7,8 +7,6 @@ const resolvePath = require('./utils').resolvePath;
const DEFAULT_FB_SOURCE_PATH = '~/fbsource/';
const DEFAULT_WWW_PATH = '~/www/';
const RELATIVE_RN_PATH = 'xplat/js/react-native-github/Libraries/Renderer/';
const RELATIVE_RN_CS_PATH = 'xplat/js/RKJSModules/Libraries/CS/downstream/';
const RELATIVE_RN_RT_PATH = 'xplat/js/RKJSModules/Libraries/RT/downstream/';
const RELATIVE_WWW_PATH = 'html/shared/react/';
async function doSync(buildPath, destPath) {
@@ -49,17 +47,7 @@ async function syncReactNative(buildPath, fbSourcePath) {
await syncReactNativeHelper(buildPath, fbSourcePath, RELATIVE_RN_PATH);
}
async function syncReactNativeCS(buildPath, fbSourcePath) {
await syncReactNativeHelper(buildPath, fbSourcePath, RELATIVE_RN_CS_PATH);
}
async function syncReactNativeRT(buildPath, fbSourcePath) {
await syncReactNativeHelper(buildPath, fbSourcePath, RELATIVE_RN_RT_PATH);
}
module.exports = {
syncReactDom,
syncReactNative,
syncReactNativeCS,
syncReactNativeRT,
};