Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can you only use expressions in JSX, not statements?

Tags:

Before proceeding, I should mention that yes, I have already read the questions and answers on "Use if statement in React JSX" and its different variants on SO and elsewhere.

However, these posts are more about how to get around without using statements in JSX. I'd like to know why statements aren't allowed in JSX, for which I cannot find any posts on.

I am reading the official documentation on this called "If-Else in JSX", and the reason given for why is, quote,

JSX is just syntactic sugar for function calls and object construction

They go on to contrast the following two pieces of code, the first of which works and the second one doesn't work:

This is valid:

// This JSX: 
ReactDOM.render(<div id="msg">Hello World!</div>, mountNode);
// Is transformed to this JS: 
ReactDOM.render(React.createElement("div", {id:"msg"}, "Hello World!"), mountNode); 

This is not valid:

// This JSX:
<div id={if (condition) { 'msg' }}>Hello World!</div>

// Is transformed to this JS:
React.createElement("div", {id: if (condition) { 'msg' }}, "Hello World!");

I would really like to understand this under the hood. First of all, in the second example, I would never have thought to write JavaScript inside the id property of an HTML element. In fact, this is the first time I've seen code of any sort used in an id property. If I were to try to write an if conditional, I would just do it in curly braces within the render return expression, as a naïve analog of other JS that works (like map or ternary expression).

render() {
return (
  {if ...
}
)

I have no doubt that it is perfectly clear to the author of this document that this slightly unorthodox example explains their assertion that "JSX is just syntactic sugar for function calls and object construction", but I cannot figure out how.

like image 768
thetrystero Avatar asked Apr 02 '20 09:04

thetrystero


2 Answers

Let's start conceptually. What are the definitions of statement vs expression?

A statement does something. An expression evaluates to a value.

JSX is meant to be built up and passed around from one segment of your code to another, eventually ending up as HTML. The name even suggests this "JavaScript to XML" conversion.

The whole point of it is to return a "value" of HTML nodes. JSX kindly allows for expressions, because those help you determine values.

Perhaps it will help to take a closer look at the difference between a ternary expression and an if/else.

If/Else

if(isSaturday){
   wakeUpHour = 10;
}else{
   wakeUpHour = 7;
}

Ternary

wakeUpHour = isSaturday ? 10 : 7;

Those both accomplish the same thing, right? But under the hood they are operating differently. In English, the if/else might read:

  1. If the value of 'isSaturday' is truthy, run the code inside the curly braces
  2. Assign the number 10 to 'wakeUpHour'
  3. Otherwise, run the code inside the next curly brace
  4. Assign the number 7 to to 'wakeUpHour'

The ternary statement also has two parts:

  1. If isSaturday is truthy, have a value of 10. Otherwise have a value 7.
  2. Assign this value to 'wakeUpHour'

We think of those as accomplishing the same thing. The key point here is that the ternary expression itself is just a value. It's not lines of codes. To do something with that value required another part, assigning it.

In JSX, we don't want to be assigning things. We want values. So we are just taking the ternary expression (a value), not the assignment part or any other code statements.

Finally, and hopefully not to add to your confusion, I would note that you can define functions in JSX.

const myJSX = <button onClick={ () => { return 'hello'; } }>Say hello</button>

Wait, what? I thought we couldn't execute lines of code. It's not executing the lines of code, it's defining them; it's rendered to:

var myJSX = React.createElement("button", {onClick: () => {
  return 'hello';
}}, "Say hello");

Compare that with trying to just throw in an if/else statement:

const myJSX = <span>{ if(true){ return 'hello'; } }</span>

Which would try to render as:

var myJSX = React.createElement("span", null, if(true){ return 'hello' });

That doesn't work, for the same reason that you can't normally pass an unencapsulated chunk of code into an argument of a function.

like image 92
tmdesigned Avatar answered Oct 02 '22 14:10

tmdesigned


Maybe this is irrelevant to your question, but I've been redirected here because one of my questions said to be duplicate to your question. if you want to do multi-line JavaScript code, you can wrap your JS code with an IIFE, for example:

  <b>
    {(() => {
      const a = [1, 2, 3].find((el) => el === 2)
      // as much code as you want ...
      // ...
      // ...
      console.log(a)
    })()}
  </b>
like image 40
Ekmek Avatar answered Oct 02 '22 14:10

Ekmek