No-el: Eliminate explicit calls to createElement() when using Python to code React applications
Tags: python, react, webdev, tutorial
Published: 2021-12-13 03:12:57

For those of you that have been utilizing the approach to creating React applications with Python from the [*React to Python*](https://pyreact.com) book, it may feel a bit kludgy having to call the `React.createElement()` function all of the time.  But doing so is a necessity since JSX isn't a very practical option when using [Transcrypt](https://www.transcrypt.org).  Or perhaps having all of those `el()`'s littering your code just makes things look a bit messier than you would prefer.  Well, I may have another option for you to try out that eliminates all of those `createElement()` calls, yet doesn't really change the way you've been writing your Python React code all that much.

Recently, a colleague was showing me some code they had written in [Jetpack Compose for Web](https://blog.jetbrains.com/kotlin/2021/05/technology-preview-jetpack-compose-for-web/), a toolkit by JetBrains which is based on Google’s platform for building reactive user interfaces with Kotlin.  It's not React, but it uses essentially the same paradigms as React.  One of the features that stood out to me when I was looking at their code was that, unlike React, the native HTML components were represented as actual component functions.  So, instead of creating React HTML elements like this as we have been doing in Python:  
```python
el('div', {'style': {'padding': '12px'}}, "Hello React!")
```
where the HTML element is represented as a string, Jetpack Compose for Web treats HTML elements as first-class citizens and uses something more like this:  
```kotlin
Div({style {padding(12.px)} }) {Text("Hello Jetpack!")}
```

Seeing that got me thinking: *"I wonder how difficult it would be to utilize that type of syntax in my own Python React projects?"*  Going into it, I knew that I would want to accomplish two things in this challenge:
1. Create wrapper functions for HTML elements so that React HTML components would be represented like any other functional React component.
2. Create a Python decorator that wraps component functions with the call to `createElement()`.

Accomplishing these two goals would effectively eliminate the need to explicitly use `createElement()` calls for generating every React element in a component tree.  Well, I'm happy to say that I accomplished both of those goals.  And it turns out that it wasn't even that difficult to do (I really do love Python!).  


## The Code
If you recall from the  [*React to Python*](https://pyreact.com) book or the [*Creating React Applications with Python*](https://dev.to/jennasys/creating-react-applications-with-python-2je1) tutorial, a module called  [*pyreact.py*](https://github.com/JennaSys/rtp_demo/blob/main/pyreact.py) is created to hold all of the code that bridges Python objects to the React JavaScript library.  It turns out that we only need to add a few more functions to this module to be able to eliminate all of the calls to `createElement()` in the rest of our Python code.

The heart of the entire solution is a single Python function that wraps a React component in a call to `createElement()` and returns that as a new function.  It looks like this:

```python
def react_component(component):  
    def react_element(props, *children):  
        return createElement(component, props, *children)  
  
    return react_element
```
If you have ever created a Python decorator, you may recognize the structure of this function.  In general terms, it is a function that takes a function as an argument and then returns a new function.  In this case, that returned function takes two (or more) arguments: `props` and zero or more `children`.  The return value of the new function is just the call to `React.createElement()` that is used in the usual way.

We will use this function in two ways.  Even though this function is structured like a decorator, there is nothing to keep us from also calling it directly.  Thanks to the dynamic nature of Python, the `component` that we pass into this function doesn't even necessarily *have* to be a function.  In fact, it can even be a string.  This feature allows us to handle the first part of our challenge in turning React HTML elements into functional components :  
```python
Div = react_component('div')
```

The string `'div'` that is passed into the function gets used as the first parameter in the call to `createElement()` in the generated function.  This is just like we were previously using it in our own Python React code.  We then save the return value of the call to `react_component('div')` in a variable called `Div` which now contains the newly generated wrapped function.

Putting all of this together, the additional code we end up adding to the updated [*pyreact.py*](https://github.com/JennaSys/rtp_demo/blob/no-el/pyreact.py) module then looks like this:

```python
def react_component(component):  
    def react_element(props, *children):  
        return createElement(component, props, *children)  
  
    return react_element
 
Form = react_component('form')  
Label = react_component('label')  
Input = react_component('input')  
Ol = react_component('ol')  
Li = react_component('li')  
Button = react_component('button')  
Div = react_component('div')  
Span = react_component('span')
```

As you can see, creating function wrappers for other React HTML elements becomes a trivial task.  Now that we have that in place, we'll next take a look at how these new functions simplify the code we use to create our React applications by eliminating the need to explicitly call `createElement()` every time ourselves.



## An Example
Starting with the [React code from the tutorial](https://github.com/JennaSys/rtp_demo), we add the necessary wrapper functions to [*pyreact.py*](https://github.com/JennaSys/rtp_demo/blob/no-el/pyreact.py) as above and then refactor the demo application to remove the calls to `createElement()`.

Listing 1: [*app.py*](https://github.com/JennaSys/rtp_demo/blob/no-el/app.py)
```python
from pyreact import useState, render, react_component  
from pyreact import Form, Label, Input, Ol, Li  
  
  
@react_component  
def ListItems(props):  
    items = props['items']  
    return [Li({'key': item}, item) for item in items]  
  
  
def App():  
    newItem, setNewItem = useState("")  
    items, setItems = useState([])  
  
    def handleSubmit(event):  
        event.preventDefault()  
        # setItems(items.__add__(newItem))  
        setItems(items + [newItem])  # __:opov  
        setNewItem("")  
  
    def handleChange(event):  
        target = event['target']  
        setNewItem(target['value'])  
  
    return Form({'onSubmit': handleSubmit},  
                Label({'htmlFor': 'newItem'}, "New Item: "),  
                Input({'id': 'newItem',  
                       'onChange': handleChange,  
                       'value': newItem  
                       }  
                      ),  
                Input({'type': 'submit'}),  
                Ol(None,  
                   ListItems({'items': items})  
                   )  
                )  
  
  
render(App, None, 'root')
```

The first thing you may notice about this refactored code is that there are no calls to `createElement()` in sight!  Removing all of those `el()`'s from the [original version of  *app.py*](https://github.com/JennaSys/rtp_demo/blob/main/app.py) has cleaned up the code quite a bit.

Now that we're not basing the HTML components on strings, we do have to import the ones we use in the module as we did here.
```python
from pyreact import Form, Label, Input, Ol, Li
```
In the `import` line above that one, we also imported the new `react_component()` function that we created in the *pyreact.py* module.  Here, we now use this as a decorator for any React functional components that we create. When we do, they will also get wrapped by the call to `createElement()` when the component gets rendered by React.

```python
@react_component  
def ListItems(props):  
    items = props['items']  
    return [Li({'key': item}, item) for item in items]
```
A side-benefit of using this decorator, is that it now becomes very easy to tell which of your Python function definitions are React components and which are just plain functions.

In this code block, you can also see the first use of our new HTML components that we use in place of the explicit call to `createElement()`.  So instead of using  
```python
el('li', {'key': item}, item)
```  
where the HTML element is identified by a string as we did before, we now use  
```python
Li({'key': item}, item)
```  
where the HTML element is a functional component itself.

The other changes we made were all in the return statement that builds the component tree.  Here, all of the calls to `createElement()` were replaced by their functional component counterparts.  All of the props and the child component structure aspects remained exactly the same as they were before making the changes.

For instructions on preparing the development environment and running the code we discussed here, you can reference the [original tutorial](https://dev.to/jennasys/creating-react-applications-with-python-2je1).  

![React App Screenshot](https://github.com/JennaSys/rtp_demo/raw/main/images/app_screenshot.png)


## Conclusion
While it is definitely subjective, for me, calling `React.createElement()` when aliased as `el()` in my Python code is but a small concession for not having JSX available to use in the Python modules.  In all honesty, it never really bothered me all that much.  But for larger components, having all of those `el()`'s cluttering up the Python code can tend to impact readability a bit.  By encapsulating the call to `createElement()` in the component itself, we can avoid having to explicitly call it in our Python code when building the element tree.

One drawback to eliminating the explicit calls to `createElement()` is that it might not be quite as evident as to what parts of your Python code are creating React elements versus just making regular function calls.  Another possible downside might be that this encapsulation of the element creation could be seen as moving away from the mental model of how React actually works.  These points are both very subjective, so you will have to decide for yourself if it makes sense to use what I've described here.

On the plus side, now that we've eliminated some of the `createElement()` code clutter, I feel that this approach makes it even less of an issue that we are not using JSX for creating React applications.  Additionally, by using defined functions instead of strings for creating HTML components, the IDE is able to help us out a little bit better when coding.


## Resources
- Source Code:
    https://github.com/JennaSys/rtp_demo/tree/no-el  
  
- Original Source Code:
    https://github.com/JennaSys/rtp_demo  

- Transcrypt Site:
    https://www.transcrypt.org  
    
- Jetpack Compose for Web:
    https://compose-web.ui.pages.jetbrains.team  
  
- Creating React Applications with Python tutorial:
    https://leanpub.com/rtptutorial  
  
- React to Python Book:
    https://pyreact.com