Visma Connect Blog

Exploring idiomatic JSX in React

Written by Jan-Willem Klomp | 12 november 2024

When I started as a programmer, I often felt like Luke Skywalker from Star Wars. Certain terms used by more senior developers would instantly fill me with awe and admiration. Words like “cyclomatic”, “memoization” and “idiomatic” dazzled me and made me painfully aware of my Padawan (intern) learner state. Luckily, over the years, the intimidating powers of the words faded and I mastered my own powers. Jedi masterhood lies ahead but to become a true Jedi, I must take my own Padawan. In this blog post, I aim to transfer my knowledge to you, the reader. The lesson for today is to help you understand what idiomatic code is, what its characteristics are, and how we can apply it in the context of React JSX. All used references are listed at the bottom of this blog.

What is ‘idiomatic’?

Outside of computer programming, you come across definitions of idiomatic as: “containing expressions that are natural and correct”. For example (see Ref 1): “She was born in Italy, but her English is fluent and idiomatic.” Not a sentence I have ever heard someone say, but maybe I hang around with the wrong people… 

Programming refers to writing code in a natural way that follows standards and best practices of a particular programming language or framework. It's about writing code that isn't only correct, but also easy for other developers to understand and maintain. 

“Writing idiomatic React code can help you write well-organized, safe, and composable applications.” (see Ref 2)

 

Idiomatic code uses language-specific features, libraries, and constructs in a way that aligns with the community's standards and norms. It emphasizes readability, conciseness, and clarity, reducing unnecessary complexity and verbosity. Keep in mind though, that what is and isn't idiomatic isn’t a law of nature but is subjective, like community standards and team preferences. 

Let's put these concepts into practice using React and JSX (or TSX when using Typescript). JSX is a syntax extension for JavaScript that lets you write HTML-like markup inside a JavaScript file. One of the great things about JSX is that you can create your components as you see fit. In a way, JSX can be thought of as a kind of domain-specific language (DSL). In essence, JSX components provide a specialized language for defining the structure, behavior, and appearance of user interfaces within React applications.

As the saying goes: “always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live” (see Ref 3). I have the fullest of confidence in my HR colleagues at Visma, so I’m pretty sure no sociopaths will get hired, but just in case, I have some additional safeguards I keep in mind while writing JSX components. They are distilled from the classic “Clean Code: A Handbook of Agile Software Craftsmanship” book (see Ref 4):

> Use Intention-Revealing Names

All of us should consider the names we give to our Component and props: A name should immediately reveal the intention of the component.

> Functions should do only one thing

In the context of React components, this means the component's render function should focus on rendering a particular UI element based on props and state. Components should not handle domain logic. 

> One Level of Abstraction per Function.

It is strongly recommended that high-level code and low-level code should not be mixed. For the JSX render function, this means we should try to avoid or limit the amount of JavaScript code (low-level) mixed with JSX (high-level). 

Using these guidelines, let’s see what idiom we can invent!

The ‘Nothing’ Component

Our journey starts small. As a React developer, you have undoubtedly used conditional rendering to display a value only if a certain condition is true. Below is an example using the JavaScript ternary operator, showcasing one of the most fundamental divides in the universe:

Where on line 5, instead of returning an empty fragment, you could also return null. Inspired by the Maybe monad’s Nothing, like in the purify-ts library (see Ref 5), we decided to make a Nothing component in React, denoting the absence of value. It’s implementation is simple:

The code now becomes:

As the “Clean Code” book advises, the component clearly states the intent that we mean to return ‘Nothing’.

The ‘Conditional’ Component

Conditional rendering is omnipresent, so why not put in a bit of extra effort and make a dedicated Conditional component? It encapsulates the conditional rendering logic and leverages the Nothing component we just created.

The condition to evaluate is passed as a property, and it uses the React ‘children’ property to render child components. For convenience, the condition can be both a boolean or a function that evaluates to a boolean.  With this new component, we can now write:

Why do I think this is an improvement over the original code? 

  • The component encapsulates a common pattern, namely, to render conditionally. 
  • By using Intention-Revealing names, the purpose of the code is easier to grasp.
  • The component encourages the One Level of Abstraction per Function rule. App.tsx has become easy to read because the JSX code has been separated from the JS code. Line 9 clearly expresses the intent to render, what to render conditionally and when to render. 

A somewhat larger example to demonstrate that the Conditional component can be used to render any number of children would be:

Here, the condition is a function that determines whether someone is a Jedi or not. If that is ‘True’, a ‘paragraph’ and a ‘JediComponent’ are rendered. 

The ‘IfElse’ Component

The next logical step is to render something both in the ’true’ or ’false’ scenario. We could, of course, use two conditional components. One for the ‘true’ case and one for the ‘false’ case. But can we do better? An option is to create an ‘IfElse’ component to capture this functionality. Those of you familiar with the programming language ColdFusion, might be reminded of the 'cfif' and ‘cfelse’ tags (see Ref 6). After some thinking and experimenting, I came up with the following:

Like in the conditional component, a condition is passed in as a prop for evaluation. However, the ‘IfElse’ component takes in an ‘If child’ and an ‘Else child’ and renders one of them depending on whether the passed condition is true or false. Children are now also explicitly mentioned as props, specifying that they must consist of exactly two ReactElements. Below is an example of the component in action:

This is a simple component where the user can click a button to increment a counter. A message is displayed that states if the current count is odd or even. It's not something that will win you a Nobel Prize, but hopefully, it helps you to get the message across.

So the question is; is this component actually an improvement? The intention of the component is quite clear, but as I mentioned, idiomaticity is subjective and should be peer-reviewed. 

After discussion, it did not meet our “violent psychopath” criteria because of the following considerations:

  • There is no built-in syntax checking, so if you forget to include the If and/or the Else component(s) as children, or mix up the order, you won’t be warned. This could be overcome by adding a runtime check on the children, but even then, you won’t get any direct feedback in your IDE. JSX elements are meant to be independent and are not part of a more elaborate programming language. 
  • Having to wrap the If and Else components makes the syntax feel verbose and clunky.

But, not to worry, the Maybe and Conditional components have made it into our production code. As mentioned above, instead of the IfElse component, we use two conditional components to do the ‘If/Else’ trick.

Summary

Although not all of my ideas were equally successful, it was a fun exercise and experiment to think of JSX in terms of a DSL where you can create your own idiom. Creating your own components can help you write clearer, intention revealing code that encourages you to adhere to clean code standards.

Hopefully, the word idiomatic has become slightly less elusive after reading this blog post. In the next part, I will explore more components, as well as look at similar work others have done in JSX. The quest for Jedi masterhood will continue…

References

  1. IDIOMATIC | definition in the Cambridge English Dictionary
  2. Rules of React 
  3. Quote by John Woods: “Always code as if the guy who ends up maintaini...” 
  4. Clean Code: A Handbook of Agile Software Craftsmanship, 1st edition 
  5. Maybe - Functional programming library for TypeScript 
  6. https://helpx.adobe.com/coldfusion/cfml-reference/coldfusion-tags/tags-i/cfif.html 

Source code for this article is available:

  1. Non-idiomatic version of the Conditional code:
    https://codesandbox.io/p/devbox/nonidiomaticreact-nrd5zv?file=%2Fsrc%2FApp.tsx 
  2. Idiomatic version of the Conditional code: https://codesandbox.io/p/devbox/wonderful-morning-5n6lkd?file=%2Fsrc%2FApp.tsx
  3. The IfElse component: https://codesandbox.io/p/sandbox/ifelse-component-hc9nln?file=%2Fsrc%2FApp.tsx