React without a build step

Alex Krolick
Sep 1, 2017 · 3 min read

TL;DR

Writing React components using React.createElement instead of JSX reduces the need for a transpiler & build system*. Components written this way:

  1. Leverage the core benefits of React — unidirectional data flow, declarative components, functional composition
  2. Can be embedded into 3rd-party sites such as CMSes and e-commerce platforms via <script> tags or snippet libraries with little hassle
  3. Are editable by anyone without setting up build tools

*If you want to target older browsers or use syntax proposals, you still need Babel, and a bundler like Webpack is great for shipping apps.

Writing a Widget

A few years ago you might have used Knockout or Backbone with jQuery to write an interactive widgets, but now React’s declarative components make these things much easier.

Suppose you’re a contractor. One of your clients, a running shoe company, asks you to build a unit converter for their webpage. Their customers need to convert miles to kilometers.

The shoe company don’t want to set up Babel or Webpack to edit the files. They run on an e-commerce platform and they want to make sure they can use the templating language and content management system it provides to maintain their pages. Luckily you can write React without any extra tooling.

Dependencies

createElement and render need to be in the global namespace. These are provided by React and ReactDOM. You can also use Preact, a lighter-weight alternative with a compatible API. (The examples use Preact.)

React

<script src="hhttps://unpkg.com/react@16.3.2/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16.3.2/umd/react-dom.production.min.js"></script>
<script>
const { createElement, Component } = React;
const { render } = ReactDOM;
const h = createElement;
</script>

Preact

<script src="https://unpkg.com/preact"></script><script>
const { createElement, render, Component } = preact;
const h = createElement;
</script>

createElement Syntax vs JSX

const h = createElement // convenient alias

Standard HTML tag with props

<div className="foo" />// equivalent
h("div", { className: "foo" })

Custom element

const Foo = props => <div className="foo" id={props.id} />
<Foo />
// equivalent
const Foo = props => h("div", { className: "foo", id: props.id })
h(Foo) // note first arg is not a string this time

Passing children

<Foo id="foo">
<Bar />
<span>Baz</span>
<Foo>
// equivalent
h(Foo, {id: "foo"}, [
h(Bar),
h("span", {}, "Baz")
])

Mile-Km Converter

The completed widget is about 80 lines and only depends on the 3kb Preact library

https://codepen.io/alexkrolick/pres/VzgeZm
https://codepen.io/alexkrolick/pres/VzgeZm

ES5?

The Javascript examples above use ES2015 syntax, which is supported in all current browsers. However, React works with prototype syntax, too. If you’re targeting older browsers or just don’t like classes, you can use prototypical inheritance like this:

https://codepen.io/alexkrolick/pres/eEbRbw
https://codepen.io/alexkrolick/pres/eEbRbw

The create-react-class library can also generate React components from plain objects in a format resembling what you'd do with the class keyword:

Impressions

Overall it’s not a bad experience. JSX makes HTML feel more at home, but tends to obscure the underlying Javascript. Composition and higher-order components are more obvious in plain JS. If I was writing a library using those patterns heavily I might be tempted to go JSX-free even if bundling with Webpack + Babel.

Resources

  • Thinking In React is a great introduction to the React way of designing components
  • Preact Docs If you want to learn more about Preact and what it can do in 3kb, start here

Discuss

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade