2021-08-23

96 line React with JSX

A while ago, I wrote a short post showing a minimal 33 line React. A lot of the comments focused on the Mithril-like syntax for the virtual DOM. So that we can ignore that aspect, here is a 96 line React with a JSX compiler.

Noughts and crosses

We're going to make this noughts and crosses game:

Now let's look at the code, you can also just view the page source if you want.

let currentPlayer = "o"
let winner = null
const g = [
    ["", "", ""],
    ["", "", ""],
    ["", "", ""],
]

const move = (value, i, j) => {
    // ... game logic goes here
    renderNoughts()
}


const Cell = ({ value, i, j }) => (
    <button class="cell" onclick={() => move(value, i, j)}>
        {value}
    </button>
)

const Noughts = () => (
    <div>
        {winner ? <marquee>winner: {winner}</marquee> : <h3>current player: {currentPlayer}</h3>}
        <table>
            {g.map((row, i) => (
                <tr>
                    {row.map((value, j) => (
                        <td class={value}>
                            <Cell value={value} i={i} j={j} />
                        </td>
                    ))}
                </tr>
            ))}
        </table>
    </div>
)

const renderNoughts = () => m.render(document.getElementById("noughts"), { children: [Noughts()] })
renderNoughts()

You can read the bread-and-butter of how it works in the original post, the only difference is, rather than use the simpler hyperscript syntax, we compile any <script type="text/jsx"> scripts to plain ol' Javascript with m.parseJsx(source).

So for example:

const Cell = ({ value, i, j }) => (
    <button class="cell" onclick={() => move(value, i, j)}>
        {value}
    </button>
)

Gets compiled to:

const Cell = ({ value, i, j }) => (
    m("button", {"class": "cell", "onclick": () => move(value, i, j), }, " ", value, " ")
)

Compiler caveats