React-native: "Text strings must be rendered within a Text component" when && operator is used in JSX

Created on 21 Aug 2018  路  24Comments  路  Source: facebook/react-native

_@hramos here. This issue has been modified from its original content, in order to convey the latest status of this issue. You may refer to the edit history to see what @mattermoran originally reported._

Environment:

[skip envinfo]

This issue only affected Android in older releases, but is now consistent across both iOS and Android platforms as of 0.57.8.

Description

Using JSX that conditionally renders a Text element can lead to a RedBox error, "Invariant Violation: Text strings must be rendered within a Text component", if the condition is "falsy", as in the following example:

<View>
  {someTextValue && <Text>{someTextValue}</Text>}
</View>

This can lead to a confusing development experience, as the pattern is documented in React's JSX docs.

Workaround

Use a ternary operator.

<View>
  {someTextValue ? <Text>{someTextValue}</Text> : null}
</View>
Bug DX Android iOS Stale 馃摦Known Issues

Most helpful comment

I know whats going wrong,

The below code works without crashing in iOS whereas it crashes in Android.
I checked it snack.expo v29.0.0.

<View style={styles.container}>
        {'' && <Text style={styles.paragraph}>I am here</Text>}
</View>

Leaving aside the crash, you should not render a empty string without wrapping it in Text for now in React-Native.
In these case you must do,

<View style={styles.container}>
        // Change any variable to boolean using double exclamation !!
        {!!'' && <Text style={styles.paragraph}>I am here</Text>}
</View>

By the way still this is a bug in RN, to maintain compatability either it should crash in both iOS and Android or it should emit omit empty string('') altogether.

All 24 comments

Can you reproduce the issue on the latest release, v0.56?

@react-native-bot I'm using create-react-native-app and I believe the latest one there is 0.52.2
I tried upgrading it to 0.56 but that caused some errors

String should not be children of View, Use Text instead.

this.state.name && <Text>{ this.state.name }</Text>

@ATShiTou sorry I just put view in the example but using Text doesn't fix the issue.

I have been using && in JSX all the time, and never crash for this.

Two layers of parentheses in your code:

this.state.name && <View>{{ this.state.name }}</View>

is wrong.

@ATShiTou my bad it should be one but then again it still crashes. I've also been using it in react and react native on ios without any problem. But for some reason same code that works just fine on ios crashes on android.

I guess that some characters are incorrect and ignored.

For this code:

<View><View />></View>

It works well on iOS, but crashes on Android.

Check your code please.

@ATShiTou Here's the screenshot of what works on ios but crashes the app on android
image
The ternary operator like this works fine on both platform
image

What about the crash log ?

@ATShiTou btw interesting thing that I noticed. Let's say I have the state nickname: null and when I fetch data and the state becomes nickname: 'alex' then app will crash. I did more tests and apparently it doesn't work with strings on android but other types like null, undefined or an object are fine. iOS handles that without a problem though. I can check logs now

UPDATE:
so actually it crashes ONLY with empty string like nickname: ''

I know whats going wrong,

The below code works without crashing in iOS whereas it crashes in Android.
I checked it snack.expo v29.0.0.

<View style={styles.container}>
        {'' && <Text style={styles.paragraph}>I am here</Text>}
</View>

Leaving aside the crash, you should not render a empty string without wrapping it in Text for now in React-Native.
In these case you must do,

<View style={styles.container}>
        // Change any variable to boolean using double exclamation !!
        {!!'' && <Text style={styles.paragraph}>I am here</Text>}
</View>

By the way still this is a bug in RN, to maintain compatability either it should crash in both iOS and Android or it should emit omit empty string('') altogether.

@ravirajn22 yes that's right. Thanks for clearing things up

Using the ternary operator is the right approach here.

Why was this bug closed? My team just got bit by this (surprising!) behavior today.

At the bare minimum if this is desired behavior (I cannot imagine how it could be), make it consistent across platforms and document it.

@jdiaz5513 it was closed as a workaround was provided. I think it's fair to aim for consistency across platforms, it's OK to open a new issue describing the desired behavior.

Follow up to my last comment: My understanding is that this is now consistent across both platforms. Previously, if you were to only test on iOS but targeted Android as well, it would be possible to ship an app to production without catching this. We now crash on both iOS and Android.

I do agree this behavior is surprising and leads to a bad DX, so I'm re-opening the issue.

@hramos Would you expect an empty string and/or 0 to not crash (and instead just act as if false or null or undefined were passed)? (That would be my vote!)

We got bit by this again last week due to the client's API switching to returning 0 instead of null in a particular area, so it started crashing without warning.

Exacerbating the problem was this ongoing issue with our exception handler, where this problem can just show a white screen and the handler doesn't actually catch the invariant exception:

https://github.com/master-atul/react-native-exception-handler/issues/52

@jamonholmgren I would expect empty strings / 0 to not crash personally, I got bit by this too, only in release.

For anyone that wants to see the errors in person
Will crash

{0 && <Text>0</Text>}
{'' && <Text>isEmptyString</Text>}

Will not crash

{undefined && <Text>isUndefined</Text>}
{true && <Text>isTrue</Text>}
{false && <Text>isFalse</Text>}
{1 && <Text>isNumber</Text>}
{null && <Text>isNull</Text>}
{'string' && <Text>isString</Text>}

{!undefined && <Text>!isUndefined</Text>}
{!true && <Text>!isTrue</Text>}
{!false && <Text>!isFalse</Text>}
{!0 && <Text>!0</Text>}
{!1 && <Text>!isNumber</Text>}
{!null && <Text>!isNull</Text>}
{!'string' && <Text>!isString</Text>}
{!'' && <Text>!isEmptyString</Text>}

got hit by this today :/ Strange error message though.
Workaround with ternary works; apart from a fix, maybe an eslint rule could help here too?
(react-native-cli: 2.0.1
react-native: 0.58.5)

Got the same error today with React Native 0.58.4. Was able to make it work by adding !! before a boolean expression. Hope this bug will be fixed in later React Native releases.

Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as a "Discussion" or add it to the "Backlog" and I will leave it open. Thank you for your contributions.

Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please feel free to create a new issue with up-to-date information.

Was this page helpful?
0 / 5 - 0 ratings