Rules
no-leaked-conditional-rendering
Full Name in @eslint-react/eslint-plugin
@eslint-react/no-leaked-conditional-renderingFull Name in eslint-plugin-react-x
react-x/no-leaked-conditional-renderingFeatures
💭
Presets
recommended-type-checked
strict-type-checked
Description
Prevents problematic leaked values from being rendered.
Using the && operator to render an element conditionally in JSX can cause unexpected values to be rendered or even crash the rendering.
Examples
In React, you might end up rendering unexpected values like 0 or NaN. In React Native, your render method will even crash if you render these values:
import React from "react";
function MyComponent() {
return <>{0 && <view />}</>;
// ^
// - Possible unexpected value will be rendered (React DOM: renders undesired '0', React Native: crashes 💥).
}import React from "react";
function MyComponent() {
return <>{NaN && <div />}</>;
// ^^^
// - Possible unexpected value will be rendered (React DOM: renders undesired 'NaN', React Native: crashes 💥).
}import React from "react";
function MyComponent() {
return <>{"" && <div />}</>;
// ^^
// - Possible unexpected value will be rendered (React DOM: renders nothing, React Native, with React below 18: crashes 💥).
}This can be avoided by:
- Coerce the value to a boolean:
{!!someValue && <Component />} - Use a ternary:
{someValue ? <Component /> : null} - Use comparisons:
{someValue > 0 && <Component />}
Failing
import React from "react";
interface MyComponentProps {
count: number;
}
function MyComponent({ count }: MyComponentProps) {
return <div>{count && <span>There are {count} results</span>}</div>;
// ^^^^^
// - Potential leaked value 'count' that might cause unintentionally rendered values or rendering crashes.
}import React from "react";
interface MyComponentProps {
items: string[];
}
function MyComponent({ items }: MyComponentProps) {
return <div>{items.length && <List items={items} />}</div>;
// ^^^^^^^^^^^^
// - Potential leaked value 'items.length' that might cause unintentionally rendered values or rendering crashes.
}import React from "react";
interface MyComponentProps {
items: string[];
}
function MyComponent({ items }: MyComponentProps) {
return <div>{items[0] && <List items={items} />}</div>;
// ^^^^^^^^
// - Potential leaked value 'items[0]' that might cause unintentionally rendered values or rendering crashes.
}import React from "react";
interface MyComponentProps {
numberA: number;
numberB: number;
}
function MyComponent({ numberA, numberB }: MyComponentProps) {
return (
<div>{(numberA || numberB) && <Results>{numberA + numberB}</Results>}</div>
// ^^^^^^^^^^^^^^^^^^^^
// - Potential leaked value '(numberA || numberB)' that might cause unintentionally rendered values or rendering crashes.
);
}Passing
import React from "react";
interface MyComponentProps {
items: string[];
}
function MyComponent({ items }: MyComponentProps) {
return <div>{items}</div>;
}import React from "react";
interface MyComponentProps {
customTitle: string;
}
const defaultTitle = "Default Title";
// An OR condition is considered valid since it's assumed to be a way to render some fallback if the first value is falsy, not to render something conditionally.
function MyComponent({ customTitle }: MyComponentProps) {
return <div>{customTitle || defaultTitle}</div>;
}import React from "react";
interface MyComponentProps {
items: string[];
}
function MyComponent({ items }: MyComponentProps) {
return <div>There are {items.length} items</div>;
}import React from "react";
interface MyComponentProps {
items: string[];
count: number;
}
function MyComponent({ items, count }: MyComponentProps) {
return <div>{!count && "No results found"}</div>;
}import React from "react";
interface MyComponentProps {
items: string[];
}
function MyComponent({ items }: MyComponentProps) {
return <div>{!!items.length && <List items={items} />}</div>;
}import React from "react";
interface MyComponentProps {
items: string[];
}
function MyComponent({ items }: MyComponentProps) {
return <div>{Boolean(items.length) && <List items={items} />}</div>;
}import React from "react";
interface MyComponentProps {
items: string[];
}
function MyComponent({ items }: MyComponentProps) {
return <div>{items.length > 0 && <List items={items} />}</div>;
}import React from "react";
interface MyComponentProps {
items: string[];
}
function MyComponent({ items }: MyComponentProps) {
return <div>{items.length ? <List items={items} /> : null}</div>;
}import React from "react";
interface MyComponentProps {
items: string[];
}
function MyComponent({ items }: MyComponentProps) {
return <div>{items.length ? <List items={items} /> : <EmptyList />}</div>;
}