Skip to content

Commit 389acdf

Browse files
committed
Expose component stack from reactTag to React Native renderer
This is not safe in general and therefore shouldn't be exposed to anything other than React Native internals. It will also need a different version in Fabric that will not have the reactTag exposed.
1 parent 27535e7 commit 389acdf

File tree

2 files changed

+93
-1
lines changed

2 files changed

+93
-1
lines changed

packages/react-native-renderer/src/ReactNativeRenderer.js

+12-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import ReactVersion from 'shared/ReactVersion';
1919
// Module provided by RN:
2020
import UIManager from 'UIManager';
2121

22+
import {getStackAddendumByWorkInProgressFiber} from 'shared/ReactFiberComponentTreeHook';
23+
2224
import NativeMethodsMixin from './NativeMethodsMixin';
2325
import ReactNativeBridgeEventPlugin from './ReactNativeBridgeEventPlugin';
2426
import ReactNativeComponent from './ReactNativeComponent';
@@ -35,6 +37,14 @@ injectFindHostInstance(ReactNativeFiberRenderer.findHostInstance);
3537

3638
ReactGenericBatching.injection.injectRenderer(ReactNativeFiberRenderer);
3739

40+
function computeComponentStackForErrorReporting(reactTag: number): string {
41+
let fiber = ReactNativeComponentTree.getClosestInstanceFromNode(reactTag);
42+
if (!fiber) {
43+
return '';
44+
}
45+
return getStackAddendumByWorkInProgressFiber(fiber);
46+
}
47+
3848
const roots = new Map();
3949

4050
const ReactNativeRenderer: ReactNativeType = {
@@ -98,7 +108,8 @@ const ReactNativeRenderer: ReactNativeType = {
98108
ReactNativePropRegistry, // flattenStyle, Stylesheet
99109
TouchHistoryMath, // PanResponder
100110
createReactNativeComponentClass, // RCTText, RCTView, ReactNativeART
101-
takeSnapshot, // react-native-implementation
111+
takeSnapshot, // react-native-implementation,
112+
computeComponentStackForErrorReporting,
102113
},
103114
};
104115

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/**
2+
* Copyright (c) 2013-present, Facebook, Inc.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @emails react-core
8+
* @jest-environment node
9+
*/
10+
11+
'use strict';
12+
13+
let React;
14+
let ReactNative;
15+
let createReactNativeComponentClass;
16+
let computeComponentStackForErrorReporting;
17+
18+
function normalizeCodeLocInfo(str) {
19+
return str && str.replace(/\(at .+?:\d+\)/g, '(at **)');
20+
}
21+
22+
describe('ReactNativeError', () => {
23+
beforeEach(() => {
24+
jest.resetModules();
25+
26+
React = require('react');
27+
ReactNative = require('react-native-renderer');
28+
createReactNativeComponentClass = require('../createReactNativeComponentClass')
29+
.default;
30+
computeComponentStackForErrorReporting =
31+
ReactNative.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
32+
.computeComponentStackForErrorReporting;
33+
});
34+
35+
it('should be able to extract a component stack from a native view', () => {
36+
const View = createReactNativeComponentClass('View', () => ({
37+
validAttributes: {foo: true},
38+
uiViewClassName: 'View',
39+
}));
40+
41+
const ref = React.createRef();
42+
43+
function FunctionalComponent(props) {
44+
return props.children;
45+
}
46+
47+
class ClassComponent extends React.Component {
48+
render() {
49+
return (
50+
<FunctionalComponent>
51+
<View foo="test" ref={ref} />
52+
</FunctionalComponent>
53+
);
54+
}
55+
}
56+
57+
ReactNative.render(<ClassComponent />, 1);
58+
59+
let reactTag = ReactNative.findNodeHandle(ref.current);
60+
61+
let componentStack = normalizeCodeLocInfo(
62+
computeComponentStackForErrorReporting(reactTag),
63+
);
64+
65+
if (__DEV__) {
66+
expect(componentStack).toBe(
67+
'\n' +
68+
' in View (at **)\n' +
69+
' in FunctionalComponent (at **)\n' +
70+
' in ClassComponent (at **)',
71+
);
72+
} else {
73+
expect(componentStack).toBe(
74+
'\n' +
75+
' in View\n' +
76+
' in FunctionalComponent\n' +
77+
' in ClassComponent',
78+
);
79+
}
80+
});
81+
});

0 commit comments

Comments
 (0)