HTML5, CSS3, jQuery, JSON, Responsive Design...

Basic ReactJS Tutorial

Michael Brown   April 3 2015 10:15:00 PM
Of JavaScript Frameworks
To say that JavaScript Frameworks have been in a state of flux in the last few years would be a truism.  Every developer seemed to zero in on jQuery and/or Bootstrap, and those two have proved to be stickers.  But then followed Backbone, Backbone+Marionette, Amber/Ember and Angular, each one the flavour of the month in a dizzying succession.  I often felt that I was spending more time attempting to learn the strengths and weaknesses of each JavaScript framework than I ever did actually writing any code in them!!

I still have a soft spot for Backbone.js, which was the first JavaScript framework at which I looked. If it doesn't do all that much for you as a developer, it's still a great way of organising your code, and its models rock! I like the way you can use as much of Backbone or as little of it as you wish, making it easy enough to add to an existing project, not just new ones. Too many of the other frameworks which I looked seem to take a "my way or the highway” approach, requiring you to rewrite everything from scratch.  You had to follow that framework's own ideology (for want of a better word) and forcing you to subscribe to its own idiosyncrasies.  Anything that you wanted to do that wasn't of its particular box seemed to be a massive pain.

Also, many of those other frameworks did not actually make much sense to me.  I tried my hardest with Ember.js and especially with Angular.js, but could not wrap my head around either of them.

Angular’s “directives embedded in HTML” approach, in particular, put me off in a big way. It just didn't look right to me, and still doesn’t.  And from what I've read in various forums, the two way data binding that is one if Angular's big selling points seems to cause as many problems as it solves, especially when applications scale to larger sizes.

Angular sure has a lot of developers using it.  How many of them still like it now is another question.  Backwards compatibility does not seem to be one of its core strengths.  I’ve seen the up-and-coming Angular.js 2.0 described as a "course change", a description that should send a shudder through any developer that's relying on it. How many of those developers are going to take kindly to rewriting their entire code base from scratch, I wonder? I think many of them may just look elsewhere instead.

In fact, I believe the Angular.js is heading for a demise that’s going to be even more rapid that was its original rise. Maybe I'm being too hard on it; and I’m not an Angular guy, after all.   Angular people can make their feelings known in the comment section of this post if they feel inclined!


Enter ReactJS

For my money, Facebook's ReactJS JavaScript library is set to dominate the Web programming world over the next year.  Even if it doesn't get as many developers as Angular or Ember, the latter two libraries are rapidly assimilating many of React's best ideas, so React will win out one way or another.

React's best features:
  1. Encourages component-based design based on composition.  Practically mandates it, in fact!
  2. Implements a one-way, top-down data flow.
  3. Has a super fast diffing engine that minimises updates to the DOM (always a performance pain).


The Tutorial

I'll attempt to demonstrate these features by a way of a small tutorial.  In this tutorial, I'll be setting up a simple, checkbox Input field.  (I said it was simple!)  But I'll set it up as a React component, to which you pass in parameters (called "props") and manage the state of that field (called, ermmm.. "state" in React!).

By "field", I mean a collection of Input fields of course, because that's how checkbox and radio fields are defined in HTML: as a collection of Input fields, grouped by their Name tag.


Let's start with an individual checkbox box element, as you might set it up in React

Example 1 - Single, Uncontrolled Checkbox Element



We start with CheckboxInput, an instance of the React class.  The class implements a single method, called "render".  This method must be supplied for every React component (the only method to be so mandated).  As you've probably guessed, the render() method tells the React component what to render as its final output.

But what's that stuff inside the render() method's return brackets?  Raw HTML?  What's that doing there?  That stuff's not legal there, surely?!!

JSX

What's actually in between the render() method's return brackets is something called JSX.  As described by Facebook, "JavaScript syntax extension that looks similar to XML".  I actually don't think it looks anything like XML, which is a good thing in my book, as I happen to loathe XML.  (Wake up!!  Use effing JSON!!!)  But I digress...

Think of JSX as a way of letting you embed raw(ish) HTML directly in your JavaScript.  It's a convenient alternative to creating a JavaScript string out of HTML to return as your output.  Does this kind of code look familiar to you?

var returnHTML = '<label><input type="checkbox" name="' + varName + '" value="' + varValue + '" \/>' + varLabel + '<\/label>'

Did I get all the double and single quotes in the right order there?  Because just one of those babies out of place and I'm stuffed, right?  Oh and you did know that every forward slash that appears in a JavaScript string has to be escaped with with backwards slash, yes?

Look at that code, and compare it again to the JSX in my first JSFiddle above it.  Which one makes it easier to understand what's going on, would you say?

JSX has other benefits too, which I'll come to later.  But for now, you should be aware that there's a cost to using JSX.  Obviously, the browser won't understand it because it's not standard JavaScript.  So, you must add a translator (or "transpiler") file called JSXTransformer.js to your project.  This file transpiles JSX to standard JavaScript on the fly, so the browser can understand it.  Yes, there's a pre-processor available so you don't have to include JSXTransformer.js in your production code.  But for development, and this tutorial, JSXTransformer is fine.

Back to Example 1 in the JSFiddle above.  After creating my CheckboxInput component, I set up some data to pass to it (the question variable), before finally calling the React.render() method to render the component.  The React.render() method takes two parameters.

The first parameter is the name of the component to render, written like an HTML tag.  Within that tag, you can pass down any number of parameters to the React component.  In React parlance, parameters passed down from to an "owned" component like this are called "props", which is short for "properties".  Note that props are said to be immutable.  They are not to be changed by the lower level component once passed down from above.  More on this later.

The second parameter the React.render() method takes is a JavaScript representation of the HTML element upon which the component is to be rendered.  (If you don't supply the second parameter, then the component will render on the page's Body tag.)

Phew!  That was a lot to go through just to get a single, input checkbox element on the page!  And one that's really doesn't do much for us either.  By which I mean, you could have done just as easily, probably more so, if you'd just used a bit of jQuery and HTML.

In particular, there's no state being monitored here.  By which I mean, if you wanted to find out whether the element was checked or not, where would you look?  There's nowhere our React code that tells you.  At the moment, you'd have to query the DOM directly to find that out, using a bit of JavaScript, and that's a big no-no.

So let's start getting React to do some more work for us.


Controlled Vs Uncontrolled

In my first example, I called my checkbox element "uncontrolled" in the title.  What does this mean?  It means what I was referring to in the previous paragraphs: i.e. that React isn't doing anything with the checkbox element in the CheckboxInput component, other than its initial render.  After that we're on our own.

With a "controlled" element, its parent React component takes care of its state and all of its updates, not just its initial render() as we had it in our first example.  See the React doco on Forms for more info on this subject.

In Example 2 below, we'll take the first steps to making our checkbox element a controlled one.

Example 2 - Single, controlled Checkbox Element, No State Update



In example 2, we've made two additions.  First, we've set up an initial state for the component, via a getInitialState() method call.  This another special React method, like the render() method.  This method must return an object that is to be the initial state of the component.  Very often, the initial state is taken, in part at least, from the props that were passed down to the component.  That's what we have done here, taking the checked parameter from props and creating a checked state from it.  (Remember, the props themselves are immutable; they should not be changed within the component that received them.)

The second addition is that we are now setting the input's checked state from the React component's checked state.  This is the line checked={this.state.checked} within our Input JSX does.

There's a step that I've deliberately left out of Example 2, however.  Before I add that step (in Example 3) I want you see what is the result of omitting that step.  Switch to the Results tab for Example 2, and then click on the "Apples" checkbox a few times.  Did you see what happened?  Absolutely nothing!

And that's as it should be.  Because we're now having the React component set the input element's "checked" state from the React component's own state, i.e. this.checked.state.  And the latter is always set to false in our code as it stands now.

Let's fix that now in Example 3.

Example 3 - Single, controlled Checkbox Element, With State Update



Two more additions here.  The first the onClick={this.handleClick} click handler line that we've added to the Input JSX.  What's that?  A click handler set up as an HTML event attribute?  Aren't we supposed to all be using JavaScript events now?   Don't worry; we are!   What you see here isn't actually an HTML event attribute.  It just looks like one for familiarity's sake.  (An actual click handler event attribute would be in all lower case: "onclick", not "onClick"!)  Once it's been through the JSXTransformer transpiler, it will be a JavaScript event.  In fact, it will become part of one big, delegated JavaScript event, along with any other "event attributes" that you might have set up in JSX.  All this you get for free, and you don't even have to think about it!

The second addition is a method that will be called by our new click handler.  I've called this method handleClick() (although we could have called it anything).  Let's take a closer look at what's going on in that method:
handleClick: function(e) {
this.setState({checked: e.target.checked});
}

The setState() method is another built-in method for a React component.  It set's the components internal state for the parameters and value supplied.  In this case, we set the React component's internal checked state to match whatever the input element's state has been set to (by the user clicking on it!) which is what we want.  (FYI, the e parameter that we've passed into the handleClick() method is an event, or to be more precise, a "synthetic event"; one which has all browser inconsistencies smoothed out.)

But the setState() method does more.  Any call to the setState() method causes the component to re-render.  Let's say that again, because it's important.  Any time you make a call the setState() method, your whole, stinking component is going to re-render onto your page.   Wow!  How crazy is that!!  I mean the performance problems alone make the dumbest thing that you could possibly do, right?

Actually, wrong.  React's superfast diffing engine, with its "shadow DOM" or "virtual DOM" feature takes care of that.  Only the parts of the DOM that really need to change are actually re-rendered to the real DOM.  And any such renders are automatically batched up, so your performance won't take a nosedive into the compost.  (This is one of those features I mentioned that the likes of Angular and Ember are now planning to add to their own frameworks.)

Here's the proof that our checkbox input is now controlled.   Switch to the Results tab for Example 3, and then click on the "Apples" checkbox a few times again.  The checkbox should now update correctly.  More importantly, the element's current DOM state is now in sync with the React component's internal checked state.  You can check this in your favourite JavaScript debugger.  Here's how it looks in the Chrome debugger, and you can see how the DOM state of the checkbox input matches that of the React component's this.state.checked.

this.state.checked in the Chrome Debugger



From Element To A Field

A single, checkbox element can be useful - think of a "Please accept these terms before proceeding" tickbox, for example.  More often that not though, you'll be wanting to present users with a range of checkbox options from which to choose.  I'll refer to such a collection of checkboxes as a "field" from this point on.  As I said earlier, a "field" in this tutorial is a collection of checkbox inputs, grouped on their name tags.

Example 4 shows how I've created such a new field-based React element, which I've called CheckboxInputField.

Example 4 - Controlled Checkbox FIeld, Poor State Implementation



If you read through the code of the new CheckboxInputField component's render() method, you can see the basic approach.  We loop through a supplied array of checkbox options (courtesy of a rewritten question variable) and return an array of CheckboxInput components.  This simple composition technique is, as I said in my introduction, one of React's key strengths.  We already have a tried and tested component, in the CheckboxInput component.  See how easy JSX makes it to compose a number of those components, before passing them to CheckboxInputField's own render() method, as the mappedInputElements array variable.

I've also included an attempt at state management in Example 4, in the form of the getRefsState() method.  The approach that I've used is a deliberately poor one, which I came up with before I'd really got my head around the way ReactJS works and what its intentions are.  (Example 5 below shows a better way to do this.)  This method works by querying each of the "owned" CheckboxInput components, in turn, to find out what each one's state is.  The see how the CheckboxInputField component is tied to its "owned" CheckboxInput components via the this.refs property.  This a pre-built React property.  In order to make use of it, you need to supply a ref value to each new, "owned" component as you are creating it, which I've done in "ref={data.value}" line in CheckboxInputField's render() method.

Although this method of state management will work, it has a major flaw: the state is in the wrong place!   If you want to know the state of CheckboxInputField component, then the state should really be held within that component.  And not in the half-assed way that I've done it, where the CheckboxInputField has to query each of its "owned" CheckboxInput components in order to determine its own state.  In truth, the individual CheckboxInput components don't even need to know what their own states are.  Their individual states only have validity insofar as they are part of the CheckboxInputField component that owns them.

This is one of React's underlying principles: state should be handled at the highest level possible in your application.  High level state is then passed down to lower level components as props.

So, let's put the state in the CheckboxInputField component in Example 5.


Example 5 - Controlled Checkbox FIeld, Better State Implementation



First, let's look at the change to the CheckboxInput component.  We still have a handleChange() method, but it doesn't do anything with the CheckboxInput component itself; certainly not setting state in there, because state is no longer handled at that level.  (And for that reason, we can also lose the CheckboxInput component's getInitialState() method.)  All the handleChange() method does now is pass some values up to its owner CheckboxInputField component.  It does this by calling the latter's handleFieldChange() method, which was passed down as a callback funciton in the CheckboxInput component's props.  This is the line "handleChange={that.handleFieldChange}" in the CheckboxInputField's render() method.

The CheckboxInputField component now gets a getInitialState() method, because that's where we're holding the state now, remember.  At this level, of course, we need to hold the state as an array, which I've called values.

The CheckboxInputField component's handleFieldChange() method is, as I said earlier, called as a callback function from within each owned CheckboxInput component, when its element is clicked by the user.  Again, the state that we're dealing with at this level is an array, so we have to take care to update the correct member of that array!  The index parameter passed up from the call from within CheckboxInput call takes care of this.  This index was, in turn, passed down from CheckboxInputField to CheckboxInput as another prop, in the line "index={x}".

Gravy!  Now we have what we wanted: state is handled at the CheckboxInputField level, giving us one place to look for the state of our field:

State handled at the CheckboxInputField level

Beware that when passing objects (and arrays are objects in JavaScript), as function parameters, they are passed by reference.  So if you're updating such objects within your function, you do need to make a copy of them first (I've used a .slice() call here to do that) otherwise you'll find yourself inadvertently updating the original object too.  This can have serious repercussions for a ReactJS setState() call, for example.


Future Enhancements

One checkbox field like this is just dandy, but what if we wanted a group of such fields?  You know, as a kind of questions and answers, survey form thing?

Well, thinking in the React way, we could create a new component called CheckboxInputFieldGroup.  This could take an array of questions and answers as its data props, and in turn, could pass that data down to an array of CheckboxInputField components that it would create.  It's that design by composition again!

There's a problem though: where would the state for a CheckboxInputFieldGroup component live?  At the moment, our state is in the CheckboxInputField components.  Damn!  Now it's a too low a level again?  "Will that boy never learn?"

Yes, we would have to refactor things to move the state higher up again.  Ideally, to higher level than even the CheckboxInputFieldGroup, to save us refactoring a third time, when we decide that level isn't high enough either!  Really, you need to be thinking at holding state at the top application level, where you deem that level to be.  The React Facebook people have an entire design approach, called Flux, to help you with that.  Flux is beyond the scope of this tutorial, however, and to be honest, I've lot looked to deeply into it myself, as yet.


Update 18/04/2015

As threatened above, I've written a Part 2 to this tutorial, where I expand the app into a "kind of questions and answers, survey form thing".



Comments

1vural  05/26/2015 3:59:11 PM  Basic ReactJS Tutorial

good arcticle

About