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
33 changes: 33 additions & 0 deletions packages/react-native-renderer/src/AssertTextIsInTextComponent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import invariant from 'shared/invariant';

export type HostContext = $ReadOnly<{|
isInAParentText: boolean,
|}>;

function stripInformation(internalInstanceHandle: Object) {
const possibleCause =
'\n\nProbably result of a conditional rendering using boolean concatination as in `cond && <Component ...>`.';
if (internalInstanceHandle && internalInstanceHandle.sibling) {
const debugOwner = internalInstanceHandle.sibling._debugOwner;
const debugSource = internalInstanceHandle.sibling._debugSource;
if (debugOwner && debugSource) {
const parentComponentName = debugOwner.type.name;
const siblingSource = `"${debugSource.fileName}" line ${debugSource.lineNumber}, column ${debugSource.columnNumber}`;
return ` Error may have occured in component <${parentComponentName}> near ${siblingSource}. ${possibleCause}`;
}
}
return possibleCause;
}

export function assertTextInTextComponent(
hostContext: HostContext,
text: string,
internalInstanceHandle: Object,
) {
invariant(
hostContext.isInAParentText,
'Text string "%s" must be rendered within a <Text> component.%s',
text,
stripInformation(internalInstanceHandle),
);
}
6 changes: 2 additions & 4 deletions packages/react-native-renderer/src/ReactFabricHostConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import type {

import {mountSafeCallback_NOT_REALLY_SAFE} from './NativeMethodsMixinUtils';
import {create, diff} from './ReactNativeAttributePayload';
import {assertTextInTextComponent} from './AssertTextIsInTextComponent';

import {enableNewReconciler} from 'shared/ReactFeatureFlags';
import invariant from 'shared/invariant';
Expand Down Expand Up @@ -250,10 +251,7 @@ export function createTextInstance(
hostContext: HostContext,
internalInstanceHandle: Object,
): TextInstance {
invariant(
hostContext.isInAParentText,
'Text strings must be rendered within a <Text> component.',
);
assertTextInTextComponent(hostContext, text, internalInstanceHandle);

const tag = nextReactTag;
nextReactTag += 2;
Expand Down
6 changes: 2 additions & 4 deletions packages/react-native-renderer/src/ReactNativeHostConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import ReactNativeFiberHostComponent from './ReactNativeFiberHostComponent';

import {DefaultLanePriority as DefaultLanePriority_old} from 'react-reconciler/src/ReactFiberLane.old';
import {DefaultLanePriority as DefaultLanePriority_new} from 'react-reconciler/src/ReactFiberLane.new';
import {assertTextInTextComponent} from './AssertTextIsInTextComponent';

const DefaultLanePriority = enableNewReconciler
? DefaultLanePriority_new
Expand Down Expand Up @@ -152,10 +153,7 @@ export function createTextInstance(
hostContext: HostContext,
internalInstanceHandle: Object,
): TextInstance {
invariant(
hostContext.isInAParentText,
'Text strings must be rendered within a <Text> component.',
);
assertTextInTextComponent(hostContext, text, internalInstanceHandle);

const tag = allocateTag();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,7 @@ describe('ReactFabric', () => {
}));

expect(() => ReactFabric.render(<View>this should warn</View>, 11)).toThrow(
'Text strings must be rendered within a <Text> component.',
'Text string "this should warn" must be rendered within a <Text> component.\n\nProbably result of a conditional rendering using boolean concatination as in `cond && <Component ...>`.',
);

expect(() =>
Expand All @@ -635,7 +635,9 @@ describe('ReactFabric', () => {
</Text>,
11,
),
).toThrow('Text strings must be rendered within a <Text> component.');
).toThrow(
'Text string "hi hello hi" must be rendered within a <Text> component.\n\nProbably result of a conditional rendering using boolean concatination as in `cond && <Component ...>`.',
);
});

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 @@ -488,7 +488,7 @@ describe('ReactNative', () => {
}));

expect(() => ReactNative.render(<View>this should warn</View>, 11)).toThrow(
'Text strings must be rendered within a <Text> component.',
'Text string "this should warn" must be rendered within a <Text> component.\n\nProbably result of a conditional rendering using boolean concatination as in `cond && <Component ...>`.',
);

expect(() =>
Expand All @@ -498,7 +498,9 @@ describe('ReactNative', () => {
</Text>,
11,
),
).toThrow('Text strings must be rendered within a <Text> component.');
).toThrow(
'Text string "hi hello hi" must be rendered within a <Text> component.\n\nProbably result of a conditional rendering using boolean concatination as in `cond && <Component ...>`.',
);
});

it('should not throw for text inside of an indirect <Text> ancestor', () => {
Expand Down
3 changes: 2 additions & 1 deletion scripts/error-codes/codes.json
Original file line number Diff line number Diff line change
Expand Up @@ -373,5 +373,6 @@
"382": "This query has received more parameters than the last time the same query was used. Always pass the exact number of parameters that the query needs.",
"383": "This query has received fewer parameters than the last time the same query was used. Always pass the exact number of parameters that the query needs.",
"384": "Refreshing the cache is not supported in Server Components.",
"385": "A mutable source was mutated while the %s component was rendering. This is not supported. Move any mutations into event handlers or effects."
"385": "A mutable source was mutated while the %s component was rendering. This is not supported. Move any mutations into event handlers or effects.",
"386": "Text string \"%s\" must be rendered within a <Text> component.%s"
}