Experiments with ReactJS

TL;DR: tried ReactJS, went back to d3js.

Web Components are on their way to a browser near us, and I’m not sure if I’m excited about them or not. On the one hand your HTML will be much easier to read and to write. On the other hand a lot of its functionality is already there in frameworks, under various names such as partials or helpers. For instance a “product” Web component could be written as:

  <product><!-- stuff --></product>

in ERB:

  < %= render partial: "products", collection: @products %>

Also, the shadow DOM is scary.

There is a polyfill you can use to play with Web components, but Reactjs also offers custom element functionality, and is being talked about a lot currently. So I spent a few days playing with it. It was interesting, but I didn’t really like it. That’s why you won’t find much react in this repository, except if you browse through its history.

Reactjs not only it brings custom elements, but also data synchronisation between backend data and the DOM.

React isn’t the first library to do it. Yet what it does really well in that it updates only the parts of the DOM that need refreshing, instead of rebuilding everything from the server. It’s fast, and saves you from doing it yourself, as I imagine it’s not trivial.

The other thing is JSX, which is what presumably confuses people the most about React. Your markup (some HTML and all your custom elements) is now in your JavaScript. You can write (From the tutorial):

var CommentBox = React.createClass({
  render: function() {
    return (
      <div className="commentBox">
        Hello, world! I am a CommentBox.
      </div>
    );
  }
});
React.render(
  <commentbox></commentbox>,
  document.getElementById('content')
);

Hmm. Maybe it’s alright. May it’s the future of web UI design and I’m not used to it yet. Maybe separating JS, HTML (and CSS) is too axiomatic and I’m too resistant to new paradigms. Let’s continue the tutorial. We come to:

render: function() {
  var commentNodes = this.props.data.map(function (comment) {
    return (
      <comment author={comment.author}>
        {comment.text}
      </comment>
    );
  });

A map to generate multiple components from data. Clever. Not the most readable, though. I think a for loop or a foreach would work better. But why not just augment JSX so you can write:

{foreach comment in this.props.data}
  <comment author={comment.author}>
    {comment.text}
  </comment>
{/foreach}

as is common in templating languages? And then you get all those messages in your javascript console about having to add keys to your custom elements, and when you look up how to do that you end up in the depths of the React documentation, which is confusing when you just want to do the tutorial. Anyway, let’s carry on.

The code I want to write is part of an application that has a dashboard which shows images on a timeline. I want that timeline to be SVG, with axes, animations, etc.

So here I go:

render: function() {
  var dayList = this.props.data.map(function (dayData) {
    return (
      <image xlink:href={dayData.thumbail} x={dayData.time} y="200"></image>
    );
  });
}

and there comes the killer console message:

error: Namespace attributes are not supported. ReactJSX is not XML.

Why can’t React just consider xlink:href as just an attribute names with a colon, I don’t know. That message is unapologetic and almost sounds as if React makes it an error on principle, because it doesn’t like namespaces.

But there is a way around it:

render: function() {
  var imageTag = '<image xlink:href="meh.jpg"></image>';
  return <svg dangerouslySetInnerHTML={{__html: imageTag }}></svg>;
}

Hacky and apparently dangerous. Not the most enticing feature of React.

At that point I’m giving up, thinking that React may well be a good idea but its execution isn’t ready yet. Hopefully it will be soon and we all learn to love JSX. Honestly, I think we won’t.

Now I’m generating my SVG using d3. I could have continued with React and gone for HTML with CSS3 transforms and all the things, but I’m more familiar with SVG+d3. So my code became:

 day.append('svg').attr('width', 1000).attr('height', 300)
    .selectAll('g')
    .data(function(d) { return d.events; })
    .enter()
    .append('image')
      .attr('xlink:href', function(d) { return d.href + '.jpg'; })
      .attr('x', function(d) { return d.time })
      .attr('y', 0)
      .attr('width', 50)
      .attr('height', 50);

Sure, the markup is still in the JavaScript code, yet the syntax is not as unsettling (especially for code editors) and is simpler and readable — not as much as with templating languages, admittedly.

True, you do need to get into the d3 way of doing the data mapping, but it’s worth it. The synchronisation isn’t as clever as React’s, either. But perhaps that will be improved, and to be fair it’s only useful for applications that do realtime updates, à la twitter or facebook.

From now on, if I want to keep investigating Web Components, I guess I’ll have to look at webcomponents.js, or keep Reactjs and forget SVG and stick to HTML, wait for native implementations or try and figure out a way to do d3 with templates.

This entry was posted in General. Bookmark the permalink.