A Fictional Account of How I Invented React

A Simplified Perspective of How React Works

A Fictional Account of How I Invented React

This past year I decided to catch up on the latest in JavaScript frameworks and learn React. Actually, it was it bit more than just learning React as I also was eager to pick up ES6 and Node. Anyway, after experiencing the complexities of Angular, Backbone, Ember, and Knockout, I found React’s clarity amazing. That said, I did, however, think that the couple books and dozens of articles I read overly complicated the simplicity of React.

I adopted a technology comprehension strategy from a mentor, Eduardo Ross (VP of Technology at ASNA), who said: “I consider how I might have coded it. And, if it’s well designed, I’m usually right.” Anyway, as I began to read more about the intricacies of React that were developed to handle edge cases my mind began to create a simplified view of how React works. I began to ignore these added features and instead develop a simplified perspective of why React was created and how it was implemented.

The following is a work of fiction but it is based on the elegance of the React framework. The story is false but the method names and behaviors are real — names of the innocent were not changed to protect them.

One Language and No Salad Dressing

I’ve been at this Web thing since before Perl scripts, PHP, and the Java Servlet API. I’ve been an author and trainer and, I’ll tell you, this mix-and-match of HTML and INSERT_LANGUAGE_HERE in Java Server Pages (JSP) or Groovy Server Pages (GSP) or Embedded RuBy (ERB) was madness. Then LiveScript came out (sorry, JavaScript) and things got yet more complicated. Using multiple languages in one file is like mixing oil and vinegar — in that they don’t mix.

Actually, that’s salad dressing, but, to make it palatable, you have to add zest and vigorously shake. It’s like your web code needs a comment: Shake brain vigorously before trying to maintain.

Salad Dressing
What I wanted (what we all wanted) was one language. One language that would rule them all. A language used to create the browser’s Document Object Model (DOM). The obvious language to use is the world’s most prevalent and pervasive — JavaScript. But its syntax would need to be similar to XHTML. So let’s call it JSX for JavaScript XHTML. The following shows the simplest React JSX you might write:

You can try this code on Codepen.io. Codepen manages the loading of the required React libraries. ReactDOM, in the above code, makes the Header 1 element render into a DOM node with the ID of root. Your React apps might have a minimal HTML page as follows:

<div id="root"></div>

But you could use React on any HTML. The <h1> contained within the element variable above looks like HTML. It is not. It is a JavaScript function called h1, implemented with the React libraries. In fact, during my delusions of creating React, I wrote JavaScript implementations for all the HTML tags. Like I said: no HTML, only JavaScript. (If you are still in ES5-land seeing ES6 transpiled to ES5 might be interesting)

The trivial example above shows the simplicity of React but, it really is not yet very useful. The pages of our applications need to be dynamic.

How might I pass data to one of these JSX components? Following our conceptual mapping of HTML syntax to JavaScript, we could use attributes. The image (img) tag, for example, has, besides the ever present id attribute, src, alt, height, and width. But, for our custom components, we will be creating our own non-HTML JSX functions and we can use any set of attributive name-value pairs. Consider the following:

The above code defines a custom JSX element called Welcome. The usage of the Welcome JSX element is in the first argument of the call to ReactDOM.render specifies two attributes: name and onClick. Name is set to simple text but onClick is an inline definition of an ES6 fat arrow function. So, using any name-value pairs we can pass any kind of data including function implementations.

I said name-value pairs but, actually, all the attributes with their values are passed as a JavaScript object. So, it’s more correct to say key-value pair.

If you try the Welcome code on codepen you’ll see the value passed via the name key is used in the “Hello from” string. Furthermore, if you click on the text, you’ll see the following in the console log:

click [object HTMLDivElement] div-id

Understand that the function executed from within the Welcome JSX function. The above code passed a JavaScript ES6 anonymous function inline with the attribute name of onClick. After all, JavaScript functions, as first class objects or citizens, can be passed around via arguments.

I’m sure you know all about JavaScript handlers for HTML events, such as those listed at w3schools. Various DOM elements generate these events. Before React, we set onclick attributes directly in HTML source code to specify JS event handlers. This gave way to unobtrusive JavaScript and the binding of element events of DOM nodes in separate scripts using jQuery or addEventListener. With React you specify the event in either inline JS code or pass a reference to a function.

Note: I did have one problem with the naming of the attribute: I found I had to use mixed-case for the handler to avoid confusion. In fact, stick with camelCase for all your JSX attributes. (Check out the React docs for DOM elements)

My use of the term, attribute, is no longer broad enough to describe key-value pairs passed to React JavaScript functions. Let’s call them properties, or just props. Properties are the magic that turns components into dynamic elements — they allow the embedding, nesting, and reuse of components.

JavaScript eXpressions

JSX statements are expressions. Their name and properties describe what behaviors their JavaScript implementations provide. Earlier I said JSX stood for JavaScript XHTML but JavaScript eXpression is more articulate.

As React is all JavaScript, your custom React component can contain other custom JSX components (as well as the standard HTML components like h1, p, ul, li, etc.).

To keep functional React components in the pure function category, their props parameter should not be modified inside the component. Or, in functional programming terms, they are considered to be immutable objects. You can always re-invoke the function with a new props object, But that gets tedious.

Class

Our complex business requirements necessitate the maintenance of application state. In object oriented programming a class is a template used to instantiate objects that contain state and methods/functions that manipulate that state. So, begrudgingly, in my invention of React, I’m going to need classes. When the state of an object instance of a React class changes, React will automatically update the browser’s DOM. To be very specific about the state that a React class is prepared to react to, those values must be contained within an instance property called, well… state.

Codepen.io hosts a simple example of a React component. The following shows the implementation of the constructor function for the component:

JustMe React application in Codepen.io

 

 

 

JustMe’s state contains mental state and state locality. (Your applications may be a bit more complex.) State is a JavaScript object that can be as complex as you’d like. What I envisioned was for React to respond to changes in the state object by turning on the properties watering hose and dowsing its nested JSX with the updated values. React would then update the DOM to reflect the values in the modified state. To manage the massive process of updating the DOM with state changes, I minimized it by requiring changes to state to be done in a function called setState. After calls to the setState method complete, the DOM refresh runs.

Consider coding state management yourself…. You have to implement some implementation of the Observable pattern. Just pondering on it now, brings back of painful memories working with updates to Angular 1’s $scope.

The handleStateChange method below embeds a call to setState change. I’ll explain in a bit why the state key is defined as a computed property. For now, suffice to say that, after setState runs, all nested JSX that display values for mental or locality will be refreshed.

Cascading Properties

The render method of your React class is where you tell React what JSX is to be, well, rendered as DOM. All the JSX functions therein are invoked passing, not just the key-value pairs of attributes in the props variable. but optionally also the state.

The codepen was created to show the flow of state through <JustMe>, <LevelTwo>, and <LevelThree>. The first line of the return clause of the two Level functions does a console.log of the passed properties:

console.log('LevelTwo props: %O', props)

The result of which, when the page loads, is:

▾ "LevelTwo props: %O" Object {
locality: "VA",
mental: "hanging on",
name: "LevelTwo",
▸ onClick: function click(e) {↔}
▸ onStateChange: function (e) {↔
}

Notice the state values of mental and locality (that were initially set in JustMe’s constructor) are passed. When these state values change in their parent component (JustMe), those props values are passed down to children and trigger a re-render of descendant components that use them (LevelTwo and LevelThree.) So in addition to cascading properties, you also get cascading updates and selective re-rendering of stuff that’s changed. Pretty cool. As I said, properties are the magic that enables the propagation of values to nested components.

Lifting State Up

LevelThree has inputs for the mental and locality values. That component is, well…, three levels down from JustMe. I explained how the values cascaded down the nested component tree, but how is the state object — maintained by the root component JustMe — going to be updated?

Property values cascade down but state updates are lifted up!

JustMe passes its handleStateChange method to LevelOne with:

onStateChange={this.handleStateChange}

I could have used any object key to hold a reference to handleStateChange, including handleStateChange but I used onStateChange to show you can use whatever name you prefer for your property’s object keys.

LevelTwo then did the same and passed everything to LevelThree. But, rather than explicitly specifying the key-value pairs as JustMe did when it called LevelThree, in LevelThree I got lazy and passed the full properties object:

Actually, it used ES6’s spread operator (...props) to create a new object. Remember: The key-value pairs specified in a JSX are passed as a JavaScript object to the function that implements the JSX.

At any rate, the LevelThree method has a reference to JustMe’s handleStateChange function. So, when the user modifies the mental or locality input fields, their DOM’s onchange event is handled by the passed properties onStateChange reference. Which, we know, came originally from JustMe. So state changes are “Lifted Up” from the following LevelThree input fields to LevelTwo back up to JustMe:

When It’s Time To StageChange (You’ve Got to Rearrange)

Change is tough, just ask Peter Brady. Now I can explain to you the implementation of handleStateChange:

It takes one argument, e, which, when onchange calls it, will be the event object. The event object has a bunch of properties one of which is target. Target has a property called name. Well, here’s the gimmick: LevelTwo defined the values for the input fields to match the object key names defined in JustMe. So, when mental state is changed to “completely nuts” the following code in:

obj[e.target.name] = e.target.value;

Executes essentially as:

state[mental]: “completely nuts”

Where the brackets contain any JavaScript expression that converts to an object property name.

This is really crazy, and I’m so impressed with my React code (which I delusionally created) that updates the DOM: but, as you type “completel” — “y nuts” not yet typed — in the mental input field, you can watch the text displayed in the JSX in JustMe as:

{this.state.mental} in {this.state.locality}

Changes from:

JustMe’s state:hanging on in VA

To:

JustMe’s state:completel in VA

For added kicks, you can click on the text displayed on the page in the div sections of LevelOne or LevelTwo and the console will display:

“LevelTwo-div clicked” or “LevelThree-div clicked”.

Note: I defined the click function stand-alone just to be different as it wasn’t necessarily a behavior specific to the JustMe component.

No Thanks to Dad

Why no inheritance? Inheritance for React provides little. In fact, React is more about nesting JSX (composition) than inheritance. A well accepted principle of OOP is: “Prefer composition over inheritance.” Actually, even though the power of classes is available in React, I recommend you start with functional components and only use class components when state is required.You will find use of pure functions will make your code easier to understand, test, reuse, and maintain.

Getting Real

OK, OK, I didn’t invent nor have anything to do with the development of React. But you already knew that because you’ve already checked Wikipedia and React’s commit log.

But, as I said, React’s clarity is amazing. It just makes sense — especially when compared to other JavaScript frameworks. React certainly has its own complexities (e.g. callbacks and context) but, for the most part, your code will be more clear without them. That said, you probably should look at React lifecycle events. I’m also quite excited about React Hooks as they let coders package state and side effects in pure functional components.

A few recommendations:

Use codepen.io:Read (and copy) other mini React apps. I want to point out that, often, when React code looks complicated, it is ES6 (or advanced JS) not React that is complicated. I had just picked up ES6 before learning React, which was good because ES6 features like spread, rest, and de-structuring are used heavily in React apps.

Get comfortable with ES6: I highly recommend the book Simplifying JavaScript.

The reactjs.org Getting Started is great and makes great use of codepen.io. I also got a lot out of the vides at the Material UI getting started.

Hey! I even came up with a clever logo for this new library!

More Insights

View All