3 Common Misconceptions about JSX

geocine

Aivan Monceller

Posted on June 5, 2020

3 Common Misconceptions about JSX

I have personally held the distaste of seeing JSX being used in React. For years, I had very strong opinions against using it until I had no other choice but to learn it.

I want to share 3 misconceptions I had and how I realized that these things were not entirely true when you look at it from a certain point of view.

You're going to find that many of the truths we cling to depend greatly on our own point of view - Obiwan Kenobi

I will not try to preach that JSX has without any flaws. As with other tools, a tool is only as good as how you would use it.

JSX is now being used even outside of React, on projects like MDX, VueJS, StencilJS, SolidJS, Mitosis, AtomicoJS and Preact. In this blog, I will be focusing on the context of React to explain my thoughts regarding JSX.

No Separation of Concerns

JSX forces us to mix JavaScript and HTML together. This means that it is trying to force us to go against the mantra of Separation of Concerns due to the mixing of layout & logic.

Here’s the thing, using JSX to write your presentation code doesn’t necessarily mean giving up these principles. Let us look at this very simple component in React

const HelloWorld = ({name}) => {
   const message = `Hello ${name}`;

   return <h1>{message}</h1>
}
Enter fullscreen mode Exit fullscreen mode

There’s no reason why that separation can’t occur in the context of JavaScript. In this example the layout & logic is separated like this:

const HelloWorld = ({name}) => {
   // component logic is confined above the JSX block
   // some logic to form message
   const message = `Hello ${name}`;

   // JSX is confined to this return block
   return <h1>{message}</h1>
}
Enter fullscreen mode Exit fullscreen mode

One important thing to note is that separation of concerns is not equal to separation of file types. In modern UI development, we have found that instead of dividing the codebase into three huge layers that interweave with one another, it makes much more sense to divide them into loosely-coupled components and compose them. Inside a component, its template, logic and styles are inherently coupled, and collocating them actually makes the component more cohesive and maintainable. - VueJS Documentation

To better understand this, let us now try converting this component into an Angular component.

@Component({
  selector: 'hello-world',
  // template is confined in this property
  template: `<h1>{{message}}</h1>`
})
export class HelloWorldComponent {
  // component logic is confined in this class
  message: String;

  @Input()
  public set name(name: string) {
    // some logic to form message
    this.message = `Hello {name}`;
  }

}
Enter fullscreen mode Exit fullscreen mode

On Angular, you can separate the template using files. I will be using MVVM/MVC terms to properly explain what is going on here.

Component Controller

@Component({
  selector: 'hello-world',
  templateUrl: './hello-world.html',
})
...
Enter fullscreen mode Exit fullscreen mode

Component View

<h1>{{message}}</h1>
Enter fullscreen mode Exit fullscreen mode

You may say that the template/layout example above is so simple so it doesn't really show the dark side of JSX. We could switch it up a bit by throwing it in a condition.

JSX

{render && <h1>{message}</h1>}
Enter fullscreen mode Exit fullscreen mode

Angular Template

<h1 *ngIf="render">{{message}}</h1>
Enter fullscreen mode Exit fullscreen mode

As you can see above they are just about the same, JSX using JavaScript & HTML, while Angular introducing *ngIf.

In this case, the conditional logic is actually mixed with the layout on both examples. Be it separated by JavaScript context in React, or separated by files in Angular.

In React, the layout is in the same file as the component. This gives you a clear idea about the component context and what is available at your disposal. However, you will likely have a very long file as time goes by even in Vue SFCs. Luckily, editors nowadays have a way to split the window so that you can work on different sections of the same file.

Even though I have stated here that you can confine JSX to the return part of the component. There is definitely no one stopping you from doing this.

const HelloWorld = ({name}) => {
   const message = <h1>{`Hello ${name}`}</h1>;

   return message;
}
Enter fullscreen mode Exit fullscreen mode

If you have to declare multiple JSX pieces across your component, think of a better way to achieve this using multiple components.

Another Templating Syntax

While JSX is claiming that it's easy to learn it because you can write HTML on JavaScript, we can think that it is actually an abomination of what we have been trying to achieve separating HTML and JavaScript.

On common frontend libraries/frameworks we have actually come up with different solutions to keep the separation between HTML from JavaScript while making HTML dynamic: Angular Template Syntax, VueJS Template Syntax.

Did you notice that there is no such thing as a JSX Template Syntax or a React Template Syntax? This is probably the only page which explains JSX and it's just a very short documentation. Though it looks like it, JSX isn’t a templating engine, in the sense that Handlebars is a templating engine, similar to what I have linked above.

JSX is actually more than that, it is a syntax extension for JavaScript. Basically, it extends JavaScript so that HTML/XML like structures can be used with JavaScript.

If you actually looked at the documentation I linked above, there is a lot to learn to get started with these templating engines as compared to JSX. In JSX, at the bare minimum, you only need to know JavaScript and HTML and a few extra exceptions. Below is an example of rendering items using a loop in JSX.

<div>
 {names.map(name => (
    <li>
      {name}
    </li>
 ))}
</div>
Enter fullscreen mode Exit fullscreen mode

Looking at this you only need to know what the JavaScript .map does, HTML div and li and the extra {} for evaluating JavaScript code. I know, this does not look clean at first, it looks like an ugly soup of JS mashed with HTML. But, let me walk you through what is happening here.

<div>{}</div>
Enter fullscreen mode Exit fullscreen mode

In JSX, HTML and JS is considered a valid JSX. However, to slap JS within an HTML you need to make use of {}. Now let us look inside the {}.

names.map(name => (<li>{name}</li>))
Enter fullscreen mode Exit fullscreen mode

This is JavaScript returning a collection of <li/> which is an HTML but is also considered valid JavaScript in JSX.

While we can think that React and JSX go against how templates are done in MVVM/MVC frameworks, that is not entirely true. Here are some templating engines on popular backend frameworks that would look very familiar to you.

Blade Templates (PHP)

<div>
@foreach ($name as $names)
   <li>{{ $name }}</li>
@endforeach
</div>
Enter fullscreen mode Exit fullscreen mode

Razor Templates (C#)

<div>
@foreach (var name in names)
{
  <li>@name</li>
}
</div>
Enter fullscreen mode Exit fullscreen mode

Jinja Templates (Python)

<div>
{% for name in names %}
  <li>{{name}}</li>
{% endfor %}
</div>
Enter fullscreen mode Exit fullscreen mode

As you can see this is about the same concept in PHP, C#, Python templating engines. You just have to know the language and some extras to actually remember it.

Now let us go back to the frontend. Let us look at the template engine of Handlebars, VueJS, Angular, and see how looping is implemented.

Handlebars

<div>
{{#each names}}
   <li>{{this}}</li>
{{/each}}
</div>
Enter fullscreen mode Exit fullscreen mode

VueJS

<div>
  <li v-for="name in names">{{name}}<li>
</div>
Enter fullscreen mode Exit fullscreen mode

Angular

<div>
  <li *ngFor="let name of names">{{ hero }}</li>
</div>
Enter fullscreen mode Exit fullscreen mode

I must admit, these look cleaner in my opinion. But, I think once the props or the attributes get into a certain number, it will be harder to identify the scope and context of control structures. You also have to remember a lot of custom attributes. Other than that, it just takes getting used to.

To drive my point home, JSX is not a templating engine but it allows us to do what another templating engine has been doing for years. On top of that, it looks very familiar since you are dealing with JavaScript and HTML.

There are more uses to JSX other than conjuring templates, you can visit the list of links I mentioned in the introduction of this article. If you don't like React, you could still consider using JSX from those projects.

Personally, it was not React that got me started to like JSX. It was StencilJS. When I finally got the hang of it, I finally considered giving React a second chance.

Too Flexible

I agree that this could be a valid rant. As with things that are too flexible, it could easily be abused. On JSX its not only JavaScript and HTML that you should look out for. It can also be used with React components which would make it confusing for someone who doesn't know React.

A React element in JSX is also a function. Hence, JSX can be used to create cryptic code such as this

You wouldn't probably be doing this although there could be some use cases for this. While I don't have the actual implementation of this code, this could be using React Context and Render Props under the hood which is specifically what React provides.

If you are looking into JSX, it's highly likely you are exploring React and wonder what Render Props are. I don't want to turn this into a React course but would just try to make a point by showing how Render Props work.

I want to create a generic Mouse component that outputs the x and y coordinates of the mouse within the component. I can then display the x and y coordinate in whatever way I like. So this is how we do it in React using Render Props.

Mouse Component (React)

const Mouse = ({children, onMouseMove}) => {
  const [coords, setCoords] = useState({x:0,y:0});

  const onMouseMove = (event) {
    setCoords({x: event.clientX, y: event.clientY});
  }
  return (<div onMouseMove={onMouseMove}>
     children({
       x: coords.x, 
       y: coords.y
     })
  </div>)
}
Enter fullscreen mode Exit fullscreen mode

Use Mouse Component (React)

<Mouse>
  ({x,y}) => {
     return <h1>The mouse position is ({x}, {y})</h1>
  }
</Mouse>
Enter fullscreen mode Exit fullscreen mode

In this example, we can see that the Mouse component accepts a function and it invokes that function on its JSX block. The function which is passed also returns a JSX.

This is somewhat similar to how high order functions work in JavaScript. A higher-order function is a function that takes a function as an argument or returns a function

Let us now try to do this in Angular.

Mouse Component (Angular)

@Component({
  selector: 'mouse',
  template: `
  <div (mousemove)="handleMouseMove($event)">
    <ng-container *ngTemplateOutlet="template; context: coords" ></ng-container>
  </div>
  `,
})
export class Mouse {
  @ContentChild(TemplateRef) template;
  coords = { x: 0, y: 0 }

  handleMouseMove(event) {
    this.coords = {
      x: event.clientX,
      y: event.clientY
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Use Mouse Component (Angular)

<mouse>
  <ng-template let-x="x" let-y="y">
     <h1>The mouse position is ({{x}}, {{y}})</h1>
  </ng-template>
</mouse>
Enter fullscreen mode Exit fullscreen mode

I can actually say that this is much harder to understand if I don't know what ng-template, ng-container, and TempalateRefare and how they actually work. With JSX, we were able to achieve what we like with shorter succinct code.

Conclusion

There is actually nothing compelling about what I’ve done here — several technologies have been using some sort of templating engine for quite some time. I still like working with templates even though I have been working with JSX nowadays.

Maybe we should start using something for a considerable amount of time before actually hating it. The use of templates vs JSX, highly depends on what application you are building, your team’s preferences, experience, or perhaps whether or not you have code-capable designers on your team.

What do you like or don't like about JSX? Please share your thoughts.

💖 💪 🙅 🚩
geocine
Aivan Monceller

Posted on June 5, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related