Repository: facebook/react
Pull request: Show a soft error when a text string or number is supplied as a child to non text wrappers

## Summary

Currently, React Native throws an invariant violation error when a text string or number is supplied as a child to non text wrappers like <View>. This is undesirable because core library components should be fault-tolerant and degrade gracefully (with soft errors, if relevant).

There is a change I am making on the native side so that it doesn't hit an assertion / crash.

## Test Plan

Modified the tests to account for the change.

Ran yarn test successfully.
Ran yarn test-prod successfully.
Ran yarn prettier successfully.
Ran yarn linc successfully.
Ran yarn flow fabric successfully.


Changed files:
filename: packages/react-native-renderer/src/ReactFabricHostConfig.js
patch: @@ -22,8 +22,6 @@ import type {
 import {mountSafeCallback_NOT_REALLY_SAFE} from './NativeMethodsMixinUtils';
 import {create, diff} from './ReactNativeAttributePayload';
 
-import invariant from 'shared/invariant';
-
 import {dispatchEvent} from './ReactFabricEventEmitter';
 
 import {
@@ -264,10 +262,11 @@ export function createTextInstance(
   hostContext: HostContext,
   internalInstanceHandle: Object,
 ): TextInstance {
-  invariant(
-    hostContext.isInAParentText,
-    'Text strings must be rendered within a <Text> component.',
-  );
+  if (__DEV__) {
+    if (!hostContext.isInAParentText) {
+      console.error('Text strings must be rendered within a <Text> component.');
+    }
+  }
 
   const tag = nextReactTag;
   nextReactTag += 2;

filename: packages/react-native-renderer/src/ReactNativeHostConfig.js
patch: @@ -147,11 +147,11 @@ export function createTextInstance(
   hostContext: HostContext,
   internalInstanceHandle: Object,
 ): TextInstance {
-  invariant(
-    hostContext.isInAParentText,
-    'Text strings must be rendered within a <Text> component.',
-  );
-
+  if (__DEV__) {
+    if (!hostContext.isInAParentText) {
+      console.error('Text strings must be rendered within a <Text> component.');
+    }
+  }
   const tag = allocateTag();
 
   UIManager.createView(

filename: packages/react-native-renderer/src/__tests__/ReactFabric-test.internal.js
patch: @@ -524,7 +524,7 @@ describe('ReactFabric', () => {
     });
   });
 
-  it('should throw for text not inside of a <Text> ancestor', () => {
+  it('should console error for text not inside of a <Text> ancestor', () => {
     const ScrollView = createReactNativeComponentClass('RCTScrollView', () => ({
       validAttributes: {},
       uiViewClassName: 'RCTScrollView',
@@ -542,7 +542,7 @@ describe('ReactFabric', () => {
       act(() => {
         ReactFabric.render(<View>this should warn</View>, 11);
       });
-    }).toThrow('Text strings must be rendered within a <Text> component.');
+    }).toErrorDev(['Text strings must be rendered within a <Text> component.']);
 
     expect(() => {
       act(() => {
@@ -553,7 +553,7 @@ describe('ReactFabric', () => {
           11,
         );
       });
-    }).toThrow('Text strings must be rendered within a <Text> component.');
+    }).toErrorDev(['Text strings must be rendered within a <Text> component.']);
   });
 
   it('should not throw for text inside of an indirect <Text> ancestor', () => {

filename: packages/react-native-renderer/src/__tests__/ReactNativeMount-test.internal.js
patch: @@ -473,7 +473,7 @@ describe('ReactNative', () => {
     );
   });
 
-  it('should throw for text not inside of a <Text> ancestor', () => {
+  it('should console error for text not inside of a <Text> ancestor', () => {
     const ScrollView = createReactNativeComponentClass('RCTScrollView', () => ({
       validAttributes: {},
       uiViewClassName: 'RCTScrollView',
@@ -487,9 +487,9 @@ 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(<View>this should warn</View>, 11),
+    ).toErrorDev(['Text strings must be rendered within a <Text> component.']);
 
     expect(() =>
       ReactNative.render(
@@ -498,7 +498,7 @@ describe('ReactNative', () => {
         </Text>,
         11,
       ),
-    ).toThrow('Text strings must be rendered within a <Text> component.');
+    ).toErrorDev(['Text strings must be rendered within a <Text> component.']);
   });
 
   it('should not throw for text inside of an indirect <Text> ancestor', () => {