diff --git a/packages/react-native-renderer/src/ReactFabricHostConfig.js b/packages/react-native-renderer/src/ReactFabricHostConfig.js index 727b782efd7..85124bb5099 100644 --- a/packages/react-native-renderer/src/ReactFabricHostConfig.js +++ b/packages/react-native-renderer/src/ReactFabricHostConfig.js @@ -262,7 +262,13 @@ export function createTextInstance( ): TextInstance { if (__DEV__) { if (!hostContext.isInAParentText) { - console.error('Text strings must be rendered within a 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 component.` + : `Text strings must be rendered within a component.`, + ); } } diff --git a/packages/react-native-renderer/src/ReactNativeHostConfig.js b/packages/react-native-renderer/src/ReactNativeHostConfig.js index 10c5e37f41b..41e29c19e2d 100644 --- a/packages/react-native-renderer/src/ReactNativeHostConfig.js +++ b/packages/react-native-renderer/src/ReactNativeHostConfig.js @@ -145,7 +145,13 @@ export function createTextInstance( internalInstanceHandle: Object, ): TextInstance { if (!hostContext.isInAParentText) { - throw new Error('Text strings must be rendered within a 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 component.` + : `Text strings must be rendered within a component.`, + ); } const tag = allocateTag(); diff --git a/packages/react-native-renderer/src/__tests__/ReactFabric-test.internal.js b/packages/react-native-renderer/src/__tests__/ReactFabric-test.internal.js index 9f2851382af..e2451af5dee 100644 --- a/packages/react-native-renderer/src/__tests__/ReactFabric-test.internal.js +++ b/packages/react-native-renderer/src/__tests__/ReactFabric-test.internal.js @@ -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', () => { @@ -538,22 +540,42 @@ describe('ReactFabric', () => { uiViewClassName: 'RCTView', })); - expect(() => { - act(() => { - ReactFabric.render(this should warn, 11); - }); - }).toErrorDev(['Text strings must be rendered within a component.']); - - expect(() => { - act(() => { - ReactFabric.render( - - hi hello hi - , - 11, - ); - }); - }).toErrorDev(['Text strings must be rendered within a component.']); + // Test both global conditions. + [ + { + debugInvalidTextStrings: true, + errors: [ + 'Text string "this should warn" must be rendered within a component.', + 'Text string "hi hello hi" must be rendered within a component.', + ], + }, + { + debugInvalidTextStrings: false, + errors: [ + 'Text strings must be rendered within a component.', + 'Text strings must be rendered within a component.', + ], + }, + ].forEach(({debugInvalidTextStrings, errors}) => { + global.debugInvalidTextStrings = debugInvalidTextStrings; + + expect(() => { + act(() => { + ReactFabric.render(this should warn, 11); + }); + }).toErrorDev([errors[0]]); + + expect(() => { + act(() => { + ReactFabric.render( + + hi hello hi + , + 11, + ); + }); + }).toErrorDev([errors[1]]); + }); }); it('should not throw for text inside of an indirect ancestor', () => { diff --git a/packages/react-native-renderer/src/__tests__/ReactNativeMount-test.internal.js b/packages/react-native-renderer/src/__tests__/ReactNativeMount-test.internal.js index 9026bef7937..fdd9cafbd45 100644 --- a/packages/react-native-renderer/src/__tests__/ReactNativeMount-test.internal.js +++ b/packages/react-native-renderer/src/__tests__/ReactNativeMount-test.internal.js @@ -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', () => { @@ -487,18 +489,38 @@ describe('ReactNative', () => { uiViewClassName: 'RCTView', })); - expect(() => ReactNative.render(this should warn, 11)).toThrow( - 'Text strings must be rendered within a component.', - ); - - expect(() => - ReactNative.render( - - hi hello hi - , - 11, - ), - ).toThrow('Text strings must be rendered within a component.'); + // Test both global conditions. + [ + { + debugInvalidTextStrings: true, + errors: [ + 'Text string "this should warn" must be rendered within a component.', + 'Text string "hi hello hi" must be rendered within a component.', + ], + }, + { + debugInvalidTextStrings: false, + errors: [ + 'Text strings must be rendered within a component.', + 'Text strings must be rendered within a component.', + ], + }, + ].forEach(({debugInvalidTextStrings, errors}) => { + global.debugInvalidTextStrings = debugInvalidTextStrings; + + expect(() => + ReactNative.render(this should warn, 11), + ).toThrow(errors[0]); + + expect(() => + ReactNative.render( + + hi hello hi + , + 11, + ), + ).toThrow(errors[1]); + }); }); it('should not throw for text inside of an indirect ancestor', () => { diff --git a/scripts/error-codes/codes.json b/scripts/error-codes/codes.json index 93391eb309d..5f794cfe883 100644 --- a/scripts/error-codes/codes.json +++ b/scripts/error-codes/codes.json @@ -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 within is not currently supported.", - "274": "Text strings must be rendered within a component.", + "274": "Text string \"%s\" must be rendered within a 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.",