mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Add unstable_enableLogBox
Summary:
This diff adds a new `unstable_enableLogBox` function to opt-into the new LogBox experience. If LogBox is not enabled early enough, we show an error with instructions.
With this, LogBox can be enabled with:
```
require('react-native').unstable_enableLogBox();
```
Changelog: [General] [Adds] unstable_enableLogBox
Reviewed By: zackargyle, rubennorte
Differential Revision: D18808940
fbshipit-source-id: 4b0234ddc4d1646515bf63110d5b02133780512e
This commit is contained in:
@@ -83,7 +83,7 @@ function reportException(e: ExtendedError, isFatal: boolean) {
|
||||
e.jsEngine == null ? message : `${message}, js engine: ${e.jsEngine}`;
|
||||
|
||||
const isHandledByLogBox =
|
||||
e.forceRedbox !== true && global.__reactExperimentalLogBox;
|
||||
e.forceRedbox !== true && global.__unstable_isLogBoxEnabled === true;
|
||||
|
||||
const data = preprocessException({
|
||||
message,
|
||||
|
||||
@@ -94,17 +94,14 @@ class AppContainer extends React.Component<Props, State> {
|
||||
}
|
||||
|
||||
render(): React.Node {
|
||||
let logBox = null;
|
||||
if (__DEV__ && !this.props.internal_excludeLogBox) {
|
||||
if (!global.__RCTProfileIsProfiling) {
|
||||
if (global.__reactExperimentalLogBox) {
|
||||
const LogBoxNotificationContainer = require('../LogBox/LogBoxNotificationContainer')
|
||||
.default;
|
||||
logBox = <LogBoxNotificationContainer />;
|
||||
} else {
|
||||
const YellowBox = require('../YellowBox/YellowBox');
|
||||
logBox = <YellowBox />;
|
||||
}
|
||||
let yellowBox = null;
|
||||
if (__DEV__) {
|
||||
if (
|
||||
!global.__RCTProfileIsProfiling &&
|
||||
!this.props.internal_excludeLogBox
|
||||
) {
|
||||
const YellowBox = require('../YellowBox/YellowBox');
|
||||
yellowBox = <YellowBox />;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,7 +135,7 @@ class AppContainer extends React.Component<Props, State> {
|
||||
<View style={styles.appContainer} pointerEvents="box-none">
|
||||
{!this.state.hasError && innerView}
|
||||
{this.state.inspector}
|
||||
{logBox}
|
||||
{yellowBox}
|
||||
</View>
|
||||
</RootTagContext.Provider>
|
||||
);
|
||||
@@ -153,13 +150,8 @@ const styles = StyleSheet.create({
|
||||
|
||||
if (__DEV__) {
|
||||
if (!global.__RCTProfileIsProfiling) {
|
||||
if (global.__reactExperimentalLogBox) {
|
||||
const LogBox = require('../LogBox/LogBox');
|
||||
LogBox.install();
|
||||
} else {
|
||||
const YellowBox = require('../YellowBox/YellowBox');
|
||||
YellowBox.install();
|
||||
}
|
||||
const YellowBox = require('../YellowBox/YellowBox');
|
||||
YellowBox.install();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -181,13 +181,15 @@ const AppRegistry = {
|
||||
* See http://facebook.github.io/react-native/docs/appregistry.html#runapplication
|
||||
*/
|
||||
runApplication(appKey: string, appParameters: any): void {
|
||||
const msg =
|
||||
'Running "' + appKey + '" with ' + JSON.stringify(appParameters);
|
||||
infoLog(msg);
|
||||
BugReporting.addSource(
|
||||
'AppRegistry.runApplication' + runCount++,
|
||||
() => msg,
|
||||
);
|
||||
if (appKey !== 'LogBox') {
|
||||
const msg =
|
||||
'Running "' + appKey + '" with ' + JSON.stringify(appParameters);
|
||||
infoLog(msg);
|
||||
BugReporting.addSource(
|
||||
'AppRegistry.runApplication' + runCount++,
|
||||
() => msg,
|
||||
);
|
||||
}
|
||||
invariant(
|
||||
runnables[appKey] && runnables[appKey].run,
|
||||
`"${appKey}" has not been registered. This can happen if:\n` +
|
||||
|
||||
@@ -12,12 +12,7 @@
|
||||
|
||||
const React = require('react');
|
||||
|
||||
import type {Category} from './Data/YellowBoxCategory';
|
||||
import type {
|
||||
Registry,
|
||||
Subscription,
|
||||
IgnorePattern,
|
||||
} from './Data/YellowBoxRegistry';
|
||||
import type {Registry, IgnorePattern} from './Data/YellowBoxRegistry';
|
||||
import * as LogBoxData from '../LogBox/Data/LogBoxData';
|
||||
type Props = $ReadOnly<{||}>;
|
||||
type State = {|
|
||||
@@ -47,14 +42,19 @@ let YellowBox;
|
||||
if (__DEV__) {
|
||||
const Platform = require('../Utilities/Platform');
|
||||
const RCTLog = require('../Utilities/RCTLog');
|
||||
const YellowBoxList = require('./UI/YellowBoxList');
|
||||
const YellowBoxContainer = require('./YellowBoxContainer').default;
|
||||
const LogBox = require('../LogBox/LogBox');
|
||||
const YellowBoxRegistry = require('./Data/YellowBoxRegistry');
|
||||
const LogBoxNotificationContainer = require('../LogBox/LogBoxNotificationContainer')
|
||||
.default;
|
||||
|
||||
// YellowBox needs to insert itself early,
|
||||
// in order to access the component stacks appended by React DevTools.
|
||||
const {error, warn} = console;
|
||||
let errorImpl = error;
|
||||
let warnImpl = warn;
|
||||
let _isLogBoxEnabled = false;
|
||||
let _isInstalled = false;
|
||||
(console: any).error = function(...args) {
|
||||
errorImpl(...args);
|
||||
};
|
||||
@@ -70,6 +70,11 @@ if (__DEV__) {
|
||||
}
|
||||
|
||||
static install(): void {
|
||||
_isInstalled = true;
|
||||
if (_isLogBoxEnabled) {
|
||||
LogBox.install();
|
||||
return;
|
||||
}
|
||||
errorImpl = function(...args) {
|
||||
error.call(console, ...args);
|
||||
// Show YellowBox for the `warning` module.
|
||||
@@ -102,46 +107,39 @@ if (__DEV__) {
|
||||
}
|
||||
|
||||
static uninstall(): void {
|
||||
if (_isLogBoxEnabled) {
|
||||
LogBox.uninstall();
|
||||
return;
|
||||
}
|
||||
_isInstalled = false;
|
||||
errorImpl = error;
|
||||
warnImpl = warn;
|
||||
delete (console: any).disableYellowBox;
|
||||
}
|
||||
|
||||
_subscription: ?Subscription;
|
||||
static __unstable_enableLogBox(): void {
|
||||
if (_isInstalled) {
|
||||
throw new Error(
|
||||
'LogBox must be enabled before AppContainer is required so that it can properly wrap the console methods.\n\nPlease enable LogBox earlier in your app.\n\n',
|
||||
);
|
||||
}
|
||||
_isLogBoxEnabled = true;
|
||||
|
||||
state = {
|
||||
registry: null,
|
||||
};
|
||||
// TODO: Temporary hack to prevent cycles with the ExceptionManager.
|
||||
global.__unstable_isLogBoxEnabled = true;
|
||||
}
|
||||
|
||||
static __unstable_isLogBoxEnabled(): boolean {
|
||||
return !!_isLogBoxEnabled;
|
||||
}
|
||||
|
||||
render(): React.Node {
|
||||
// TODO: Ignore warnings that fire when rendering `YellowBox` itself.
|
||||
return this.state.registry == null ? null : (
|
||||
<YellowBoxList
|
||||
onDismiss={this._handleDismiss}
|
||||
onDismissAll={this._handleDismissAll}
|
||||
registry={this.state.registry}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
this._subscription = YellowBoxRegistry.observe(registry => {
|
||||
this.setState({registry});
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount(): void {
|
||||
if (this._subscription != null) {
|
||||
this._subscription.unsubscribe();
|
||||
if (_isLogBoxEnabled) {
|
||||
return <LogBoxNotificationContainer />;
|
||||
}
|
||||
}
|
||||
|
||||
_handleDismiss = (category: Category): void => {
|
||||
YellowBoxRegistry.delete(category);
|
||||
};
|
||||
|
||||
_handleDismissAll(): void {
|
||||
YellowBoxRegistry.clear();
|
||||
// TODO: Ignore warnings that fire when rendering `YellowBox` itself.
|
||||
return <YellowBoxContainer />;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -162,6 +160,13 @@ if (__DEV__) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
static __unstable_enableLogBox(): void {
|
||||
// Do nothing.
|
||||
}
|
||||
static __unstable_isLogBoxEnabled(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
render(): React.Node {
|
||||
return null;
|
||||
}
|
||||
@@ -172,5 +177,7 @@ module.exports = (YellowBox: Class<React.Component<Props, State>> & {
|
||||
ignoreWarnings($ReadOnlyArray<IgnorePattern>): void,
|
||||
install(): void,
|
||||
uninstall(): void,
|
||||
__unstable_enableLogBox(): void,
|
||||
__unstable_isLogBoxEnabled(): boolean,
|
||||
...
|
||||
});
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const React = require('react');
|
||||
|
||||
import type {Category} from './Data/YellowBoxCategory';
|
||||
import type {Registry, Subscription} from './Data/YellowBoxRegistry';
|
||||
|
||||
type Props = $ReadOnly<{||}>;
|
||||
type State = $ReadOnly<{|
|
||||
registry: ?Registry,
|
||||
|}>;
|
||||
|
||||
const YellowBoxList = require('./UI/YellowBoxList');
|
||||
const YellowBoxRegistry = require('./Data/YellowBoxRegistry');
|
||||
|
||||
class YellowBoxContainer extends React.Component<Props, State> {
|
||||
_subscription: ?Subscription;
|
||||
|
||||
state: State = {
|
||||
registry: null,
|
||||
};
|
||||
|
||||
render(): React.Node {
|
||||
// TODO: Ignore warnings that fire when rendering `YellowBox` itself.
|
||||
return this.state.registry == null ? null : (
|
||||
<YellowBoxList
|
||||
onDismiss={this._handleDismiss}
|
||||
onDismissAll={this._handleDismissAll}
|
||||
registry={this.state.registry}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
this._subscription = YellowBoxRegistry.observe(registry => {
|
||||
this.setState({registry});
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount(): void {
|
||||
if (this._subscription != null) {
|
||||
this._subscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
_handleDismiss = (category: Category): void => {
|
||||
YellowBoxRegistry.delete(category);
|
||||
};
|
||||
|
||||
_handleDismissAll(): void {
|
||||
YellowBoxRegistry.clear();
|
||||
}
|
||||
}
|
||||
|
||||
export default YellowBoxContainer;
|
||||
@@ -11,8 +11,16 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as React from 'react';
|
||||
const YellowBox = require('../YellowBox');
|
||||
const YellowBoxRegistry = require('../Data/YellowBoxRegistry');
|
||||
const LogBoxData = require('../../LogBox/Data/LogBoxData');
|
||||
const render = require('../../../jest/renderer');
|
||||
|
||||
jest.mock('../../LogBox/LogBoxNotificationContainer', () => ({
|
||||
__esModule: true,
|
||||
default: 'LogBoxNotificationContainer',
|
||||
}));
|
||||
|
||||
describe('YellowBox', () => {
|
||||
const {error, warn} = console;
|
||||
@@ -74,4 +82,49 @@ describe('YellowBox', () => {
|
||||
(console: any).error('Warning: ...');
|
||||
expect(YellowBoxRegistry.add).toBeCalled();
|
||||
});
|
||||
|
||||
it('if LogBox is enabled, installs and uninstalls LogBox', () => {
|
||||
jest.mock('../../LogBox/Data/LogBoxData');
|
||||
jest.mock('../Data/YellowBoxRegistry');
|
||||
|
||||
YellowBox.__unstable_enableLogBox();
|
||||
YellowBox.install();
|
||||
|
||||
(console: any).warn('Some warning');
|
||||
expect(YellowBoxRegistry.add).not.toBeCalled();
|
||||
expect(LogBoxData.addLog).toBeCalled();
|
||||
expect(YellowBox.__unstable_isLogBoxEnabled()).toBe(true);
|
||||
|
||||
YellowBox.uninstall();
|
||||
(LogBoxData.addLog: any).mockClear();
|
||||
|
||||
(console: any).warn('Some warning');
|
||||
expect(YellowBoxRegistry.add).not.toBeCalled();
|
||||
expect(LogBoxData.addLog).not.toBeCalled();
|
||||
expect(YellowBox.__unstable_isLogBoxEnabled()).toBe(true);
|
||||
});
|
||||
|
||||
it('throws if LogBox is enabled after YellowBox is installed', () => {
|
||||
jest.mock('../Data/YellowBoxRegistry');
|
||||
|
||||
YellowBox.install();
|
||||
|
||||
expect(() => YellowBox.__unstable_enableLogBox()).toThrow(
|
||||
'LogBox must be enabled before AppContainer is required so that it can properly wrap the console methods.\n\nPlease enable LogBox earlier in your app.\n\n',
|
||||
);
|
||||
});
|
||||
|
||||
it('should render YellowBoxContainer by default', () => {
|
||||
const output = render.shallowRender(<YellowBox />);
|
||||
|
||||
expect(output).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render LogBoxNotificationContainer when LogBox is enabled', () => {
|
||||
YellowBox.__unstable_enableLogBox();
|
||||
|
||||
const output = render.shallowRender(<YellowBox />);
|
||||
|
||||
expect(output).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`YellowBox should render LogBoxNotificationContainer when LogBox is enabled 1`] = `<LogBoxNotificationContainer />`;
|
||||
|
||||
exports[`YellowBox should render YellowBoxContainer by default 1`] = `<YellowBoxContainer />`;
|
||||
@@ -438,6 +438,9 @@ module.exports = {
|
||||
get unstable_RootTagContext(): RootTagContext {
|
||||
return require('./Libraries/ReactNative/RootTagContext');
|
||||
},
|
||||
get unstable_enableLogBox(): () => void {
|
||||
return require('./Libraries/YellowBox/YellowBox').__unstable_enableLogBox;
|
||||
},
|
||||
|
||||
// Prop Types
|
||||
get ColorPropType(): DeprecatedColorPropType {
|
||||
|
||||
Reference in New Issue
Block a user