export default function App() {
const item = undefined;
const Item = () => item && <div>{item.name}</div>;
return (
<div>
<Item />
</div>
);
}
In our case, item is initialized from array.find. It is a react-bootstrap NavDropdown.Item with others in a NavDropdown. It produces a white screen in our app rather than the on-screen errors seen in the example, but the javascript console shows the same errors. Changing to ternary item ? <div>{item.name}</div> : null works as a workaround.
React version:
^16.12.0
Link to code example:
https://codesandbox.io/s/kind-voice-t2mdo
Error
Item(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null.
skip rendering, no errors, as it does if item is null.
There's difference between undefined and null.
In JavaScript, because of hoisting, all identifiers are anticipated implicitly with a value of undefined till a value is explicitly set to the identifier, which means variables that are declared and not yet defined, or not yet declared are anticipated with a definition of undefined (funny right? defined with undefined).
Talk about null, this is an identifier declared and defined, but with no true value.
Think of undefined as an empty tube which is a vacuum and null also as an empty tube, but filled with air. If you look inside the tube you see nothing, therefore you say it's empty, but there's air.
If Javascript was as strict as other langs, undefined will always throw an error.
The error you get in the console is a useful one, at least to make certain you know what you are doing return null, which means it's intentionally empty.
React really has no way to distinguish a component that implicitly returns undefined from one that explicitly returns undefined. All functions return void/undefined implicitly. So this error is useful. At that point you can go back to your source and check whether you inadvertently omitted a return statement. The only way to tell if the component returns nothing explicitly is to return null as functions don't return null implicitly.
The issue is that boolean short circuiting treats the values (null, NaN, 0, empty string ("" or '' or ``), undefined) the same, so I think it natural to expect react to treat them the same, and what this documentation indicates:
https://reactjs.org/docs/conditional-rendering.html#inline-if-with-logical--operator
Oddly, it works inline but not pulled into a separate component.
The component expects returned a value to be at least null object.
const Item1 = () => undefined
const Item2 = () => null
const Item3 = () => <>{undefined}</>
const el1 = <Item1 /> // this doesn't work
const el2 = <Item2 /> // this works
const el3 = <Item3 /> // this works
Not sure about reason for react to require returning null explicitly when component doesn't have anything to render.
@illuminist I think it's because forgetting to return something from a function in javascript, returns undefined by default. So React catches a lot of bugs early by not letting the undefined as the return type of the components, especially in complicated conditional renders.
But null is always intentional.
The error you get in the console is a useful one, at least to make certain you know what you are doing
return null, which means it's intentionally empty.
React really has no way to distinguish a component that implicitly returnsundefinedfrom one that explicitly returnsundefined. All functions return void/undefined implicitly. So this error is useful. At that point you can go back to your source and check whether you inadvertently omitted a return statement. The only way to tell if the component returns nothing explicitly is toreturn nullas functions don't returnnullimplicitly.
That's my point here. But I think @jestrickler still didn't get it.
@calebpitan I get your points. Assuming ignorance does not come across well. I realize it's behaving as designed, and there are some good reasons why it's that way. I'm just debating why I, and others, might expect different behavior and leaving it up to the React.js authorities to consider.
As for catching bugs early, I think if nothing is rendered because you accidentally returned undefined, you'd catch that quickly anyway. To me, the behavior of boolean short-circuiting within a component, and that it's inconsistent with the same thing inlined, was more of a surprise:
{item && <div>{item.name}</div>}
const Item = () => item && <div>{item.name}</div>;
What if just returning a _falsy_ value indicated to render nothing?
@jestrickler If item is undefined, then:
<>{item && <div>{item.name}</div>}</> is equal to <>{undefined}</>
const Item = () => item && <div>{item.name}</div> is equal to const Item = () => undefined
Note the first case, the component is returning Fragment with undefined children, and second case is just returning undefined.
@illuminist yeah, I get that they're not exactly the same, and your earlier comment that enumerated the options was great:
const Item1 = () => undefined
const Item2 = () => null
const Item3 = () => <>{undefined}</>
const el1 = <Item1 /> // this doesn't work
const el2 = <Item2 /> // this works
const el3 = <Item3 /> // this works
I would add to that
const Item = () => NaN // works, displays NaN
const Item = () => 0 // works, displays 0
const Item = () => "" // works
But I kinda feel that they should behave the same... Maybe that's just me..?
I should note there is also another problem in your original example:
export default function App() {
const item = undefined;
const Item = () => item && <div>{item.name}</div>;
return (
<div>
<Item />
</div>
);
}
Here you are generating a different Item component on every render which causes it to lose any state in the subtree. Don鈥檛 do that.
The reason for the behavior is it鈥檚 very easy to return undefined accidentally and not realize why nothing renders.
function Button() {
<button />
}
We found that problem to be much more common in practice that the one in this post.
@gaearon on your comment about 'another problem'... I think I know (/am learning) what you mean. At least I recently got familiar with '@welldone-software/why-did-you-render' and 'memo' But I do that sort of thing a lot just for code organization, and I think I've seen it in plenty of examples/tutorials. Can you elaborate a bit on the issue and proper handling or point me to any relevant documentation?
Most helpful comment
@illuminist I think it's because forgetting to return something from a function in javascript, returns
undefinedby default. So React catches a lot of bugs early by not letting theundefinedas the return type of the components, especially in complicated conditional renders.But
nullis always intentional.