React sync (16 beta 6 plus addons)

Reviewed By: sebmarkbage

Differential Revision: D4775005

fbshipit-source-id: c50d099dc3d01c10e122c56f11bd990a2b1e81d1
This commit is contained in:
Brian Vaughn 2017-03-27 16:54:08 -07:00 committed by Facebook Github Bot
parent 92d985fb49
commit 6f9447e7b2
6 changed files with 197 additions and 74 deletions

View File

@ -11,4 +11,4 @@
'use strict';
module.exports = '16.0.0-alpha.4';
module.exports = '16.0.0-alpha.6';

View File

@ -102,11 +102,6 @@ var ReactNativeEventEmitter = {
) {
var nativeEvent = nativeEventParam || EMPTY_NATIVE_EVENT;
var inst = ReactNativeComponentTree.getInstanceFromNode(rootNodeID);
if (!inst) {
// If the original instance is already gone, we don't have to dispatch
// any events.
return;
}
ReactGenericBatching.batchedUpdates(function() {
ReactNativeEventEmitter.handleTopLevel(
topLevelType,

View File

@ -267,3 +267,97 @@ it('handles when a responder is unmounted while a touch sequence is in progress'
expect(getResponderId()).toBe('two');
expect(log).toEqual(['two responder start']);
});
it('handles events without target', () => {
var EventEmitter = RCTEventEmitter.register.mock.calls[0][0];
var View = createReactNativeComponentClass({
validAttributes: {id: true},
uiViewClassName: 'View',
});
function getViewById(id) {
return UIManager.createView.mock.calls.find(
args => args[3] && args[3].id === id,
)[0];
}
function getResponderId() {
const responder = ResponderEventPlugin._getResponder();
if (responder === null) {
return null;
}
const props = typeof responder.tag === 'number'
? responder.memoizedProps
: responder._currentElement.props;
return props ? props.id : null;
}
var log = [];
function render(renderFirstComponent) {
ReactNative.render(
<View id="parent">
<View key={1}>
{renderFirstComponent
? <View
id="one"
onResponderEnd={() => log.push('one responder end')}
onResponderStart={() => log.push('one responder start')}
onStartShouldSetResponder={() => true}
/>
: null}
</View>
<View key={2}>
<View
id="two"
onResponderEnd={() => log.push('two responder end')}
onResponderStart={() => log.push('two responder start')}
onStartShouldSetResponder={() => true}
/>
</View>
</View>,
1,
);
}
render(true);
EventEmitter.receiveTouches(
'topTouchStart',
[{target: getViewById('one'), identifier: 17}],
[0],
);
// Unmounting component 'one'.
render(false);
EventEmitter.receiveTouches(
'topTouchEnd',
[{target: getViewById('one'), identifier: 17}],
[0],
);
expect(getResponderId()).toBe(null);
EventEmitter.receiveTouches(
'topTouchStart',
[{target: getViewById('two'), identifier: 18}],
[0],
);
expect(getResponderId()).toBe('two');
EventEmitter.receiveTouches(
'topTouchEnd',
[{target: getViewById('two'), identifier: 18}],
[0],
);
expect(getResponderId()).toBe(null);
expect(log).toEqual([
'one responder start',
'two responder start',
'two responder end',
]);
});

View File

@ -12,8 +12,13 @@
'use strict';
const emptyFunction = require('fbjs/lib/emptyFunction');
const invariant = require('fbjs/lib/invariant');
import type {CapturedError} from 'ReactFiberScheduler';
let showDialog = emptyFunction;
function logCapturedError(capturedError: CapturedError): void {
if (__DEV__) {
const {
@ -80,6 +85,22 @@ function logCapturedError(capturedError: CapturedError): void {
`React caught an error thrown by one of your components.\n\n${error.stack}`,
);
}
showDialog(capturedError);
}
exports.injection = {
injectDialog(fn: (e: CapturedError) => void) {
invariant(
showDialog === emptyFunction,
'The custom dialog was already injected.',
);
invariant(
typeof fn === 'function',
'Injected showDialog() must be a function.',
);
showDialog = fn;
},
};
exports.logCapturedError = logCapturedError;

View File

@ -12,8 +12,70 @@
'use strict';
const invariant = require('fbjs/lib/invariant');
let caughtError = null;
let invokeGuardedCallback = function(name, func, context, a, b, c, d, e, f) {
const funcArgs = Array.prototype.slice.call(arguments, 3);
try {
func.apply(context, funcArgs);
} catch (error) {
return error;
}
return null;
};
if (__DEV__) {
/**
* To help development we can get better devtools integration by simulating a
* real browser event.
*/
if (
typeof window !== 'undefined' &&
typeof window.dispatchEvent === 'function' &&
typeof document !== 'undefined' &&
typeof document.createEvent === 'function'
) {
const fakeNode = document.createElement('react');
let depth = 0;
invokeGuardedCallback = function(name, func, context, a, b, c, d, e, f) {
depth++;
const thisDepth = depth;
const funcArgs = Array.prototype.slice.call(arguments, 3);
const boundFunc = function() {
func.apply(context, funcArgs);
};
let fakeEventError = null;
const onFakeEventError = function(event) {
// Don't capture nested errors
if (depth === thisDepth) {
fakeEventError = event.error;
}
};
const evtType = `react-${name ? name : 'invokeguardedcallback'}-${depth}`;
window.addEventListener('error', onFakeEventError);
fakeNode.addEventListener(evtType, boundFunc, false);
const evt = document.createEvent('Event');
evt.initEvent(evtType, false, false);
fakeNode.dispatchEvent(evt);
fakeNode.removeEventListener(evtType, boundFunc, false);
window.removeEventListener('error', onFakeEventError);
depth--;
return fakeEventError;
};
}
}
let rethrowCaughtError = function() {
if (caughtError) {
const error = caughtError;
caughtError = null;
throw error;
}
};
/**
* Call a function while guarding against errors that happens within it.
* Returns an error if it throws, otherwise null.
@ -24,6 +86,16 @@ let caughtError = null;
* @param {...*} args Arguments for function
*/
const ReactErrorUtils = {
injection: {
injectErrorUtils(injectedErrorUtils: Object) {
invariant(
typeof injectedErrorUtils.invokeGuardedCallback === 'function',
'Injected invokeGuardedCallback() must be a function.',
);
invokeGuardedCallback = injectedErrorUtils.invokeGuardedCallback;
},
},
invokeGuardedCallback: function<A, B, C, D, E, F, Context>(
name: string | null,
func: (a: A, b: B, c: C, d: D, e: E, f: F) => void,
@ -35,13 +107,7 @@ const ReactErrorUtils = {
e: E,
f: F,
): Error | null {
const funcArgs = Array.prototype.slice.call(arguments, 3);
try {
func.apply(context, funcArgs);
} catch (error) {
return error;
}
return null;
return invokeGuardedCallback.apply(this, arguments);
},
/**
@ -75,64 +141,8 @@ const ReactErrorUtils = {
* we will rethrow to be handled by the top level error handler.
*/
rethrowCaughtError: function() {
if (caughtError) {
const error = caughtError;
caughtError = null;
throw error;
}
return rethrowCaughtError.apply(this, arguments);
},
};
if (__DEV__) {
/**
* To help development we can get better devtools integration by simulating a
* real browser event.
*/
if (
typeof window !== 'undefined' &&
typeof window.dispatchEvent === 'function' &&
typeof document !== 'undefined' &&
typeof document.createEvent === 'function'
) {
const fakeNode = document.createElement('react');
let depth = 0;
ReactErrorUtils.invokeGuardedCallback = function(
name,
func,
context,
a,
b,
c,
d,
e,
f,
) {
depth++;
const thisDepth = depth;
const funcArgs = Array.prototype.slice.call(arguments, 3);
const boundFunc = function() {
func.apply(context, funcArgs);
};
let fakeEventError = null;
const onFakeEventError = function(event) {
// Don't capture nested errors
if (depth === thisDepth) {
fakeEventError = event.error;
}
};
const evtType = `react-${name ? name : 'invokeguardedcallback'}-${depth}`;
window.addEventListener('error', onFakeEventError);
fakeNode.addEventListener(evtType, boundFunc, false);
const evt = document.createEvent('Event');
evt.initEvent(evtType, false, false);
fakeNode.dispatchEvent(evt);
fakeNode.removeEventListener(evtType, boundFunc, false);
window.removeEventListener('error', onFakeEventError);
depth--;
return fakeEventError;
};
}
}
module.exports = ReactErrorUtils;

View File

@ -128,7 +128,7 @@
"react-native": "local-cli/wrong-react-native.js"
},
"peerDependencies": {
"react": "~16.0.0-alpha.4"
"react": "16.0.0-alpha.6"
},
"dependencies": {
"absolute-path": "^0.0.0",
@ -187,6 +187,9 @@
"plist": "^1.2.0",
"pretty-format": "^4.2.1",
"promise": "^7.1.1",
"react-addons-create-fragment": "15.5.0-alpha.0",
"react-addons-pure-render-mixin": "15.5.0-alpha.0",
"react-addons-shallow-compare": "15.5.0-alpha.0",
"react-clone-referenced-element": "^1.0.1",
"react-devtools-core": "^2.0.8",
"react-timer-mixin": "^0.13.2",
@ -224,9 +227,9 @@
"jest-repl": "19.0.2",
"jest-runtime": "19.0.2",
"mock-fs": "^3.11.0",
"react": "~16.0.0-alpha.4",
"react-dom": "~16.0.0-alpha.4",
"react-test-renderer": "~16.0.0-alpha.3",
"react": "16.0.0-alpha.6",
"react-dom": "16.0.0-alpha.6",
"react-test-renderer": "16.0.0-alpha.6",
"shelljs": "0.6.0",
"sinon": "^2.0.0-pre.2"
}