Skip to content

Commit

Permalink
Use HostContext to warn about invalid View/Text nesting (#12766)
Browse files Browse the repository at this point in the history
  • Loading branch information
bvaughn authored May 14, 2018
1 parent c5d3104 commit c802d29
Show file tree
Hide file tree
Showing 8 changed files with 352 additions and 141 deletions.
45 changes: 37 additions & 8 deletions packages/react-native-renderer/src/ReactFabricRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import * as ReactNativeViewConfigRegistry from 'ReactNativeViewConfigRegistry';
import ReactFiberReconciler from 'react-reconciler';

import deepFreezeAndThrowOnMutationInDev from 'deepFreezeAndThrowOnMutationInDev';
import emptyObject from 'fbjs/lib/emptyObject';
import invariant from 'fbjs/lib/invariant';

// Modules provided by RN:
import TextInputState from 'TextInputState';
Expand All @@ -35,6 +35,10 @@ import UIManager from 'UIManager';
// This means that they never overlap.
let nextReactTag = 2;

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

/**
* This is used for refs on host components.
*/
Expand Down Expand Up @@ -135,7 +139,7 @@ const ReactFabricRenderer = ReactFiberReconciler({
type: string,
props: Props,
rootContainerInstance: Container,
hostContext: {},
hostContext: HostContext,
internalInstanceHandle: Object,
): Instance {
const tag = nextReactTag;
Expand All @@ -151,6 +155,11 @@ const ReactFabricRenderer = ReactFiberReconciler({
}
}

invariant(
type !== 'RCTView' || !hostContext.isInAParentText,
'Nesting of <View> within <Text> is not currently supported.',
);

const updatePayload = ReactNativeAttributePayload.create(
props,
viewConfig.validAttributes,
Expand All @@ -175,9 +184,14 @@ const ReactFabricRenderer = ReactFiberReconciler({
createTextInstance(
text: string,
rootContainerInstance: Container,
hostContext: {},
hostContext: HostContext,
internalInstanceHandle: Object,
): TextInstance {
invariant(
hostContext.isInAParentText,
'Text strings must be rendered within a <Text> component.',
);

const tag = nextReactTag;
nextReactTag += 2;

Expand All @@ -203,12 +217,27 @@ const ReactFabricRenderer = ReactFiberReconciler({
return false;
},

getRootHostContext(): {} {
return emptyObject;
getRootHostContext(rootContainerInstance: Container): HostContext {
return {isInAParentText: false};
},

getChildHostContext(): {} {
return emptyObject;
getChildHostContext(
parentHostContext: HostContext,
type: string,
): HostContext {
const prevIsInAParentText = parentHostContext.isInAParentText;
const isInAParentText =
type === 'AndroidTextInput' || // Android
type === 'RCTMultilineTextInputView' || // iOS
type === 'RCTSinglelineTextInputView' || // iOS
type === 'RCTText' ||
type === 'RCTVirtualText';

if (prevIsInAParentText !== isInAParentText) {
return {isInAParentText};
} else {
return parentHostContext;
}
},

getPublicInstance(instance) {
Expand All @@ -230,7 +259,7 @@ const ReactFabricRenderer = ReactFiberReconciler({
oldProps: Props,
newProps: Props,
rootContainerInstance: Container,
hostContext: {},
hostContext: HostContext,
): null | Object {
const viewConfig = instance.canonical.viewConfig;
const updatePayload = ReactNativeAttributePayload.diff(
Expand Down
44 changes: 37 additions & 7 deletions packages/react-native-renderer/src/ReactNativeFiberRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import type {ReactNativeBaseComponentViewConfig} from './ReactNativeTypes';
import ReactFiberReconciler from 'react-reconciler';
import emptyObject from 'fbjs/lib/emptyObject';
import invariant from 'fbjs/lib/invariant';

// Modules provided by RN:
import UIManager from 'UIManager';
import deepFreezeAndThrowOnMutationInDev from 'deepFreezeAndThrowOnMutationInDev';
Expand All @@ -35,6 +36,10 @@ export type Instance = {
type Props = Object;
type TextInstance = number;

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

// Counter for uniquely identifying views.
// % 10 === 1 means it is a rootTag.
// % 2 === 0 means it is a Fabric tag.
Expand Down Expand Up @@ -71,7 +76,7 @@ const NativeRenderer = ReactFiberReconciler({
type: string,
props: Props,
rootContainerInstance: Container,
hostContext: {},
hostContext: HostContext,
internalInstanceHandle: Object,
): Instance {
const tag = allocateTag();
Expand All @@ -85,6 +90,11 @@ const NativeRenderer = ReactFiberReconciler({
}
}

invariant(
type !== 'RCTView' || !hostContext.isInAParentText,
'Nesting of <View> within <Text> is not currently supported.',
);

const updatePayload = ReactNativeAttributePayload.create(
props,
viewConfig.validAttributes,
Expand All @@ -110,9 +120,14 @@ const NativeRenderer = ReactFiberReconciler({
createTextInstance(
text: string,
rootContainerInstance: Container,
hostContext: {},
hostContext: HostContext,
internalInstanceHandle: Object,
): TextInstance {
invariant(
hostContext.isInAParentText,
'Text strings must be rendered within a <Text> component.',
);

const tag = allocateTag();

UIManager.createView(
Expand Down Expand Up @@ -155,12 +170,27 @@ const NativeRenderer = ReactFiberReconciler({
return false;
},

getRootHostContext(): {} {
return emptyObject;
getRootHostContext(rootContainerInstance: Container): HostContext {
return {isInAParentText: false};
},

getChildHostContext(): {} {
return emptyObject;
getChildHostContext(
parentHostContext: HostContext,
type: string,
): HostContext {
const prevIsInAParentText = parentHostContext.isInAParentText;
const isInAParentText =
type === 'AndroidTextInput' || // Android
type === 'RCTMultilineTextInputView' || // iOS
type === 'RCTSinglelineTextInputView' || // iOS
type === 'RCTText' ||
type === 'RCTVirtualText';

if (prevIsInAParentText !== isInAParentText) {
return {isInAParentText};
} else {
return parentHostContext;
}
},

getPublicInstance(instance) {
Expand All @@ -181,7 +211,7 @@ const NativeRenderer = ReactFiberReconciler({
oldProps: Props,
newProps: Props,
rootContainerInstance: Container,
hostContext: {},
hostContext: HostContext,
): null | Object {
return emptyObject;
},
Expand Down
Loading

0 comments on commit c802d29

Please sign in to comment.