[RT] More predictable things (#11139)

* Inject the right event emitter

Previously this was injecting the ReactNativeEventEmitter even though
we want the ReactNativeRTEventEmitter.

RCTEventEmitter is also just an abstraction around BatchedBridge that
registers a single name. We can't register more than one with it. Removed
that abstraction for now so we don't have to add it back into the RN repo.

* Unify appendChildToDetachedParent and appendChild, separate root

Merge appendChildToDetachedParent and appendChild. We don't need the distinction.

We do however need a separate notion for the root container.
Calling this `appendChildToContext` since Context has a meaning here.

* Add a simple shallow comparison so that we don't send updates for equal props

This still sends all props if any differs. Not sure we'll want that but I
think so.

* Add BatchedBridge to bundle externals

* Lint
This commit is contained in:
Sebastian Markbåge 2017-10-06 19:08:22 -07:00 committed by GitHub
parent 190a1141cc
commit 5744571140
8 changed files with 78 additions and 23 deletions

View File

@ -93,13 +93,13 @@ declare module 'RTManager' {
classType : string,
props : ?Object,
) : void;
declare function appendChildToDetachedParent(
parentTag : number,
childTag : number,
) : void;
declare function beginUpdates() : void;
declare function appendChildToContext(
contextTag : number,
childTag : number,
) : void;
declare function appendChild(
parentTag : number,
childTag : number,
@ -118,3 +118,10 @@ declare module 'RTManager' {
declare function completeUpdates() : void;
}
declare module 'BatchedBridge' {
declare function registerCallableModule(
name : string,
module : Object,
) : void;
}

View File

@ -302,7 +302,7 @@ const bundles = [
'ExceptionsManager',
'InitializeCore',
'Platform',
'RCTEventEmitter',
'BatchedBridge',
'RTManager',
'prop-types/checkPropTypes',
],

View File

@ -0,0 +1,14 @@
/**
* 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';
var BatchedBridge = {
registerCallableModule: jest.fn(),
};
module.exports = BatchedBridge;

View File

@ -11,11 +11,11 @@
var RCTRTManager = {
createNode: jest.fn(function createView(tag, classType, props) {}),
appendChildToDetachedParent: jest.fn(function appendChildToDetachedParent(
parentTag,
beginUpdates: jest.fn(function beginUpdates() {}),
appendChildToContext: jest.fn(function appendChildToContext(
contextTag,
childTag,
) {}),
beginUpdates: jest.fn(function beginUpdates() {}),
appendChild: jest.fn(function appendChild(parentTag, childTag) {}),
prependChild: jest.fn(function prependChild(childTag, beforeTag) {}),
deleteChild: jest.fn(function deleteChild(childTag) {}),

View File

@ -11,6 +11,7 @@
var ReactNativeRTComponentTree = require('ReactNativeRTComponentTree');
var ReactGenericBatching = require('ReactGenericBatching');
var BatchedBridge = require('BatchedBridge');
var ReactNativeRTEventEmitter = {
/**
@ -40,4 +41,7 @@ var ReactNativeRTEventEmitter = {
},
};
module.exports = ReactNativeRTEventEmitter;
BatchedBridge.registerCallableModule(
'RTEventEmitter',
ReactNativeRTEventEmitter,
);

View File

@ -32,13 +32,7 @@ import type {ReactNodeList} from 'ReactTypes';
*/
require('InitializeCore');
var RCTEventEmitter = require('RCTEventEmitter');
var ReactNativeEventEmitter = require('ReactNativeEventEmitter');
/**
* Register the event emitter with the native bridge
*/
RCTEventEmitter.register(ReactNativeEventEmitter);
require('ReactNativeRTEventEmitter');
ReactGenericBatching.injection.injectFiberBatchedUpdates(
ReactNativeRTFiberRenderer.batchedUpdates,

View File

@ -45,6 +45,29 @@ function processProps(instance: number, props: Props): Object {
return propsPayload;
}
function arePropsEqual(oldProps: Props, newProps: Props): boolean {
var 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({
appendChild(parentInstance: Instance, child: Instance | TextInstance): void {
RTManager.appendChild(parentInstance, child);
@ -54,14 +77,14 @@ const NativeRTRenderer = ReactFiberReconciler({
parentInstance: Container,
child: Instance | TextInstance,
): void {
RTManager.appendChild(parentInstance, child);
RTManager.appendChildToContext(parentInstance, child);
},
appendInitialChild(
parentInstance: Instance,
child: Instance | TextInstance,
): void {
RTManager.appendChildToDetachedParent(parentInstance, child);
RTManager.appendChild(parentInstance, child);
},
commitTextUpdate(
@ -90,7 +113,7 @@ const NativeRTRenderer = ReactFiberReconciler({
internalInstanceHandle: Object,
): void {
updateFiberProps(instance, newProps);
RTManager.updateNode(instance, processProps(instance, newProps));
RTManager.updateNode(instance, updatePayload);
},
createInstance(
@ -165,7 +188,10 @@ const NativeRTRenderer = ReactFiberReconciler({
rootContainerInstance: Container,
hostContext: {},
): null | Object {
return emptyObject;
if (arePropsEqual(oldProps, newProps)) {
return null;
}
return processProps(instance, newProps);
},
removeChild(parentInstance: Instance, child: Instance | TextInstance): void {

View File

@ -25,7 +25,8 @@ describe('ReactNativeRT', () => {
it('should be able to create and render a native component', () => {
ReactNativeRT.render(<rt-box foo="test" />, 1);
expect(RTManager.createNode).toBeCalled();
expect(RTManager.appendChild).toBeCalled();
expect(RTManager.appendChildToContext).toBeCalled();
expect(RTManager.appendChild).not.toBeCalled();
expect(RTManager.updateNode).not.toBeCalled();
});
@ -34,13 +35,22 @@ describe('ReactNativeRT', () => {
expect(RTManager.createNode.mock.calls.length).toBe(1);
expect(RTManager.createNode).toBeCalledWith(1, 'rt-box', {foo: 'foo'});
expect(RTManager.appendChild.mock.calls.length).toBe(1);
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.appendChild.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);
});
});