question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Conditional rendering against an empty string causes application to crash with cryptic error message

See original GitHub issue

Description

* Note: I’m not sure if this is an issue with React Native, or React itself. If it turns out to be a React problem, I can file an issue over there instead; just let me know.

When using conditional rendering in JSX with the && operator, using a variable containing the empty string ("") as the render condition causes React Native to blow up with the following error message:

Invariant Violation: Text strings must be rendered within a <Text> component.

I did not find the error message to be helpful, and it took several hours of debugging and searching to find the cause of the problem. This StackOverflow question is what finally gave me the information I needed to solve the problem. I found this issue incredibly annoying and time consuming, and I’m sure it would be incredibly helpful to future developers if either (a) React Native just dealt with this issue silently, or (b) the error message provided something more helpful.

React Native version:

System:
    OS: macOS 11.0
    CPU: (12) x64 Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
    Memory: 55.63 MB / 16.00 GB
    Shell: 5.8 - /bin/zsh
  Binaries:
    Node: 12.18.1 - /var/folders/xc/tfq34tzd54qgz7njmw2rvs3w0000gn/T/yarn--1600464068569-0.5536557097021451/node
    Yarn: 1.22.4 - /var/folders/xc/tfq34tzd54qgz7njmw2rvs3w0000gn/T/yarn--1600464068569-0.5536557097021451/yarn
    npm: 6.14.5 - ~/.nvm/versions/node/v12.18.1/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman
  Managers:
    CocoaPods: 1.9.3 - /Users/kjensen/.gem/bin/pod
  SDKs:
    iOS SDK:
      Platforms: iOS 14.0, DriverKit 19.0, macOS 10.15, tvOS 14.0, watchOS 7.0
    Android SDK:
      API Levels: 30
      Build Tools: 30.0.2
      Android NDK: Not Found
  IDEs:
    Android Studio: 4.1 RC 3 4.1 RC 3
    Xcode: 12.0/12A7209 - /usr/bin/xcodebuild
  Languages:
    Java: 14.0.1 - /usr/bin/javac
    Python: 2.7.16 - /usr/bin/python
  npmPackages:
    @react-native-community/cli: Not Found
    react: ~16.13.1 => 16.13.1 
    react-native: ~0.63.2 => 0.63.2 
    react-native-macos: Not Found
  npmGlobalPackages:
    *react-native*: Not Found

Steps To Reproduce

Provide a detailed list of steps that reproduce the issue.

  1. Create a JSX or TSX file in your React Native project that includes something like this:

    import React from 'react';
    import { View, Text } from 'react-native'; 
    
    export const MyComponent: React.FC = () => {
      const text: string | undefined = ""; // Presumably, this value would come from some external source, like an API call.
      return (
        <View>
          {text && <Text>{text}</Text>}
        </View>
      );
    };
    
  2. Import MyComponent and add it to the render function of one of your existing components (like App.tsx).

  3. Build and run your application.

Expected Results

I expected my <Text/> component to render if the value of text was truthy, and not to render if its value was falsy. In the above case, "" is falsy, so I expect that the component does not render.

Actual Results

The application blows up at runtime with the following exception:

Invariant Violation: Text strings must be rendered within a <Text> component.

Workarounds

Performing explicit boolean coercion on text allows the component to render properly:

{!!text && <Text>{text}</Text>}

Unfortunately, there is no way that a new developer would know to do this without first encountering the problem, then spending the time to find the solution on StackOverflow or in this issue. It’s also possible that the developer might not ever encounter the issue in development, and might only realize that an issue exists after seeing something about it in production crash logs.

I considered writing a custom ESLint rule to warn about this, but I wasn’t able to find a way to get it working without causing a bunch of false positives, (i.e. using conditional rendering where the condition is actually a boolean), so I think a better solution would be if RN handled this in the platform.

Snack, code example, screenshot, or link to a repository:

See above.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:5 (1 by maintainers)

github_iconTop GitHub Comments

3reactions
chrisbobbecommented, Sep 21, 2020

Thanks for explaining your experience in detail!

It’s true that the && operator is tricky in JavaScript and prone to “gotcha” moments like this one. Here’s a doc about it from MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_AND

To quote from it, take this example:

expr1 && expr2

If expr1 can be converted to true, returns expr2; else, returns expr1.

If a value can be converted to true, the value is so-called truthy. If a value can be converted to false, the value is so-called falsy.

This is consistent with what’s happening to you; expr1 in your case is the empty string, which isn’t truthy, so the expression evaluates to the empty string (not, e.g., false or null, etc.); this would be the case even outside React and React Native.

The problem comes when React Native’s View component doesn’t want to handle a string (including an empty string) as its direct child; instead, to show some text, React Native wants you to use Text. I think this is accurately indicated by the error you’re seeing: "Invariant Violation: Text strings must be rendered within a <Text> component", even if that message by itself isn’t very precise about what lines of your code are causing a problem. In earlier versions of React Native, the error wasn’t a complete sentence like this; it was full of irrelevant-looking identifiers that the app developer isn’t normally concerned about, the crash only occurred on Android (meaning a nasty surprise if you did most of your testing on iOS), and (IIRC) left no trail in the component hierarchy that would lead you to the specific component that had to be examined. Do you at least get a trail like that?

The React docs make a brief mention of this strategy for conditional rendering. But (perhaps disingenuously) it only covers the left-hand side being true or false, and not what happens if it’s merely truthy or falsy—leaving it up to the programmer’s luck of how familiar they are with the quirks of &&.

I think in general being making sure the left-hand side is a boolean is a good pattern. In React on the web, rendering the empty string as a child of an element, for example, is allowed, just as it obviously is in plain HTML. But if the case were slightly different, and the left-hand side were a number (e.g., with {things.length && <ListOfThings things={things} />), you could end up with an unexpected 0 appearing somewhere on the page and have no idea how it got there.

Anyway, a few points for where I think this could go:

  • Does the error output indicate the specific component or file where the error is thrown from?
  • Maybe that React doc could be improved.
0reactions
KingAmocommented, Jan 19, 2021
<View>
 {0 && <Text>test</Text>}
</View>

this will lead to Text strings must be rendered within a <Text> component. error in my case

in fact this code result

<View>0</View>

and react native do not allow text inside a View component

Read more comments on GitHub >

github_iconTop Results From Across the Web

Conditional rendering in React Native may crash your app
Empty string is falsy so AND operator will return '' because the condition is not fulfilled. Returning '' directly into ReactNative JSX will ......
Read more >
Using conditional rendering with empty strings - Stack Overflow
This trick only works with booleans, null, undefined and 0. React tries to render the string even if it is empty.
Read more >
A Common Conditional Rendering Bug in React Native
This is a common React pattern and is perfectly fine. The problem however, is that in React Native, rendering a string, even an...
Read more >
Release Notes - HEAVY.AI Docs
Improves import status error message when an invalid request is made. ... Fixes an issue that caused an intermittent KafkaImporter crash on CentOS...
Read more >
What went wrong? Troubleshooting JavaScript - MDN Web Docs
These errors generally mean that you've left off a string value's opening or closing quote mark. In the first error above, string would...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found