Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion packages/react-native-renderer/src/ReactFabricHostConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,13 @@ export function createTextInstance(
): TextInstance {
if (__DEV__) {
if (!hostContext.isInAParentText) {
console.error('Text strings must be rendered within a <Text> component.');
console.error(
// Opt-in detailed error messages
// Learn More: https://github.com/facebook/react/pull/22725#issuecomment-1006023545
global.debugInvalidTextStrings
? `Text string "${text}" must be rendered within a <Text> component.`
: `Text strings must be rendered within a <Text> component.`,
);
}
}

Expand Down
8 changes: 7 additions & 1 deletion packages/react-native-renderer/src/ReactNativeHostConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,13 @@ export function createTextInstance(
internalInstanceHandle: Object,
): TextInstance {
if (!hostContext.isInAParentText) {
throw new Error('Text strings must be rendered within a <Text> component.');
throw new Error(
// Opt-in detailed error messages
// Learn More: https://github.com/facebook/react/pull/22725#issuecomment-1006023545
global.debugInvalidTextStrings
? `Text string "${text}" must be rendered within a <Text> component.`
: `Text strings must be rendered within a <Text> component.`,
);
}

const tag = allocateTag();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ describe('ReactFabric', () => {
.ReactNativeViewConfigRegistry.register;

act = require('jest-react').act;

delete global.debugInvalidTextStrings;
});

it('should be able to create and render a native component', () => {
Expand Down Expand Up @@ -538,22 +540,42 @@ describe('ReactFabric', () => {
uiViewClassName: 'RCTView',
}));

expect(() => {
act(() => {
ReactFabric.render(<View>this should warn</View>, 11);
});
}).toErrorDev(['Text strings must be rendered within a <Text> component.']);

expect(() => {
act(() => {
ReactFabric.render(
<Text>
<ScrollView>hi hello hi</ScrollView>
</Text>,
11,
);
});
}).toErrorDev(['Text strings must be rendered within a <Text> component.']);
// Test both global conditions.
[
{
debugInvalidTextStrings: true,
errors: [
'Text string "this should warn" must be rendered within a <Text> component.',
'Text string "hi hello hi" must be rendered within a <Text> component.',
],
},
{
debugInvalidTextStrings: false,
errors: [
'Text strings must be rendered within a <Text> component.',
'Text strings must be rendered within a <Text> component.',
],
},
].forEach(({debugInvalidTextStrings, errors}) => {
global.debugInvalidTextStrings = debugInvalidTextStrings;

expect(() => {
act(() => {
ReactFabric.render(<View>this should warn</View>, 11);
});
}).toErrorDev([errors[0]]);

expect(() => {
act(() => {
ReactFabric.render(
<Text>
<ScrollView>hi hello hi</ScrollView>
</Text>,
11,
);
});
}).toErrorDev([errors[1]]);
});
});

it('should not throw for text inside of an indirect <Text> ancestor', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ describe('ReactNative', () => {
.ReactNativeViewConfigRegistry.register;
TextInputState = require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface')
.TextInputState;

delete global.debugInvalidTextStrings;
});

it('should be able to create and render a native component', () => {
Expand Down Expand Up @@ -487,18 +489,38 @@ describe('ReactNative', () => {
uiViewClassName: 'RCTView',
}));

expect(() => ReactNative.render(<View>this should warn</View>, 11)).toThrow(
'Text strings must be rendered within a <Text> component.',
);

expect(() =>
ReactNative.render(
<Text>
<ScrollView>hi hello hi</ScrollView>
</Text>,
11,
),
).toThrow('Text strings must be rendered within a <Text> component.');
// Test both global conditions.
[
{
debugInvalidTextStrings: true,
errors: [
'Text string "this should warn" must be rendered within a <Text> component.',
'Text string "hi hello hi" must be rendered within a <Text> component.',
],
},
{
debugInvalidTextStrings: false,
errors: [
'Text strings must be rendered within a <Text> component.',
'Text strings must be rendered within a <Text> component.',
],
},
].forEach(({debugInvalidTextStrings, errors}) => {
global.debugInvalidTextStrings = debugInvalidTextStrings;

expect(() =>
ReactNative.render(<View>this should warn</View>, 11),
).toThrow(errors[0]);

expect(() =>
ReactNative.render(
<Text>
<ScrollView>hi hello hi</ScrollView>
</Text>,
11,
),
).toThrow(errors[1]);
});
});

it('should not throw for text inside of an indirect <Text> ancestor', () => {
Expand Down
2 changes: 1 addition & 1 deletion scripts/error-codes/codes.json
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@
"270": "The current renderer does not support persistence. This error is likely caused by a bug in React. Please file an issue.",
"271": "Failed to replay rendering after an error. This is likely caused by a bug in React. Please file an issue with a reproducing case to help us find it.",
"273": "Nesting of <View> within <Text> is not currently supported.",
"274": "Text strings must be rendered within a <Text> component.",
"274": "Text string \"%s\" must be rendered within a <Text> component.",
"275": "The current renderer does not support mutation. This error is likely caused by a bug in React. Please file an issue.",
"276": "React depends on requestAnimationFrame. Make sure that you load a polyfill in older browsers. https://reactjs.org/link/react-polyfills",
"277": "Context.unstable_read(): Context can only be read while React is rendering, e.g. inside the render method or getDerivedStateFromProps.",
Expand Down