In this blog post, I explore another form of truthiness in Javascript. What happens if you use a bitwise operator on a value like 0|value or ~~value.

Context

We recently turned on the JSHint bitwise rule by default and the following code was caught.

var isValid = false;
for (var i = 0; i < elements.length; ++i) {
  isValid |= elements.someProperty;
}
return isValid;

The author didn't mean to use a bitwise operator and wanted to write the following instead:

  isValid = isValid || elements.someProperty;

Unfortunately, while the two lines look similar, they do not behave the same for all Javascript values. Instead of using the truthiness rules, the value is first converted to a signed 32bit integer and compared against 0.

Booleans and special values

In this system, booleans and special values are behaving as expected:

  • 0 | undefined === 0
  • 0 | null === 0
  • 0 | false === 0
  • 0 | true === 1

Numbers

It becomes a bit more tricky with numbers. The double is first converted to signed 32 bits integer and then compared to 0.

For usual integers, it is working as expected, only 0 is falsy.

  • 0 | 0 === 0
  • 0 | 1 === 1
  • 0 | 42 === 42
  • 0 | -1 === -1

NaN (not a number) is considered as falsy, still going as expected.

  • 0 | NaN === 0

For non integers, it is more tricky. Any number in the range ]-1, 1[ is going to be falsy. Lines highlighted in yellow do not behave the same as normal truthy values.

  • 0 | 0.99 === 0
  • 0 | -0.99 === 0
  • 0 | 1.01 === 1

For big integers, the situation is even more confusing. They are all truthy except multiples of 232. This is true even after 253.

  • 0 | Math.pow(2, 32) === 0
  • 0 | 3 * Math.pow(2, 32) === 0
  • 0 | Math.pow(2, 53) === 0
  • 0 | Math.pow(2, 60) === 0
  • 0 | Math.pow(2, 32) + 1 === 1

Strings

Contrary to normal truthiness, strings in general are falsy.

  • 0 | "" === 0
  • 0 | " " === 0
  • 0 | "a" === 0

But, strings that represent numbers now follow number rules.

  • 0 | "0" === 0
  • 0 | "1" === 1
  • 0 | "0.5" === 0

The number parser is not rigid and accept inputs that have whitespace around for example.

  • 0 | "    1    " === 1

Objects

Objects are first converted to string before being converted to int32. So nearly all objects are falsy because their string representation is "[object Object]".

  • 0 | {} === 0
  • 0 | {key: 1} === 0

You can still craft objects that passes that check by overriding toString.

  • 0 | {toString: function() { return "1"; }} === 1

Conclusion

The normal truthiness rules can be quite misleading, but if you want to shoot yourself in the foot, I highly encourage you to replace all your !!expression into 0|expression. This will give you endless hours of debugging fun.

Dealing with scroll position when you insert content is usually a difficult problem to solve. We'll see how to use React life cycle methods to solve it elegantly.

Insertion at the bottom

The first example is to maintain the scroll position at the bottom when an element is inserted at the bottom. A common use case is a chat application.

In order to scroll at the bottom, we can do that on componentDidUpdate. It happens every time the element is re-rendered.

componentDidUpdate: function() {
  var node = this.getDOMNode();
  node.scrollTop = node.scrollHeight;
},

But this is going to always scroll to the bottom, which can be very annoying if you want to read what was above. Instead you want to scroll only if the user was already at the bottom. To do that, we can check the scroll position before the component has updated with componentWillUpdate and scroll if necessary at componentDidUpdate

componentWillUpdate: function() {
  var node = this.getDOMNode();
  this.shouldScrollBottom = node.scrollTop + node.offsetHeight === node.scrollHeight;
},
 
componentDidUpdate: function() {
  if (this.shouldScrollBottom) {
    var node = this.getDOMNode();
    node.scrollTop = node.scrollHeight
  }
},

Note: we use this.shouldScrollBottom = ...; and not this.setState({shouldScrollBottom: ...}); because we don't want to trigger another render. We just need to manage that value between the two events.

Insertion at the top

The other use case is adding elements at the top of the page but doing so without screwing up the current scroll position of the user. An example is a log view where you can scroll to the top to read historical context.

This is using a similar technique. On componentWillUpdate we store the scroll position and on componentDidUpdate we scroll to the added delta.

componentWillUpdate: function() {
  var node = this.getDOMNode();
  this.scrollHeight = node.scrollHeight;
  this.scrollTop = node.scrollTop;
},
 
componentDidUpdate: function() {
  var node = this.getDOMNode();
  node.scrollTop = this.scrollTop + (node.scrollHeight - this.scrollHeight);
},

Conclusion

React has not been designed to handle scroll position natively. However, it provides escape hatches from the declarative paradigm in order to be able to implement them.

React is bundled with a Javascript transpiler called JSX. It gives the ability to write <html> tags within Javascript. The advertised way to use JSX is React.DOM to create React light DOM elements, but it is not the only way. We can create another JSX backend, called JSXDOM, to create real DOM elements.

Example

Here is an example (JSFiddle) of how the code looks like with JSX and JSXDOM:

/** @jsx JSXDOM */
 
var defaultValue = "Fill me ...";
 
document.body.appendChild(
  <div>
    <input type="text" value={defaultValue} />
    <button onclick="alert('clicked!');">Click Me!</button>
    <ul>
      {['un', 'deux', 'trois'].map(function(number) {
        return <li>{number}</li>;
      })}
    </ul>
  </div>
);

Advantages

There are many libs that attempt to do this in pure Javascript (dom-o, htmlr, ThinAir ...) but none of them look like XML. With JSX, you can copy and paste HTML in your Javascript code and it works (if you close your tags).

The great benefit outside of looking like XML is interpolation. Anything you put inside of {} is a regular Javascript expression. This way you don't need to learn yet another templating language.

var defaultValue = "Fill me ...";
<input type="text" value={defaultValue} />

It is useful for attributes but even more for children. You can create any array using Javascript functions such as map, filter, reduce, reverse ... and pass it down to JSXDOM.

<ul>
  {['un', 'deux', 'trois'].map(function(number) {
    return <li>{number}</li>;
  })}
</ul>

Conclusion

JSX is a very exciting technology that, while being developed for React, can be used standalone and provide benefits on its own.

Multiple people asked what's the story about JSX and CoffeeScript. There is no JSX pre-processor for CoffeeScript and I'm not aware of anyone working on it. (If you are interested in writing one, you probably should look at CoffeeScriptRedux). Fortunately, CoffeeScript is pretty expressive and we can play around the syntax to come up with something that is usable.

Example

Let's see how JSX look like with an example:

<div classname="MarkdownEditor">
 
 
<h3>Input</h3>
 
 
  <textarea onkeyup="{this.handleKeyUp}" ref="textarea">    {this.state.value}
  </textarea>
</div>

which desugars to the following

React.DOM.div({className: 'MarkdownEditor'}, [
  React.DOM.h3({}, 'Input'),
  React.DOM.textarea({onKeyUp: this.handleKeyUp, ref: 'textarea'},
    this.state.value
  )
])

We can easily translate it to CoffeeScript:

{div, h3, textarea} = React.DOM
(div {className: 'MarkdownEditor'}, [
  (h3 {}, 'Input'),
  (textarea {onKeyUp: @handleKeyUp, ref: 'textarea'},
    @state.value
  )
])

Structure

The translations rules are really easy. The only gotcha is to write the tags wrapped in parenthesis lisp-style. This is the best way I found not to get caught with indentation issues.

# Empty element
#
 
 
<div></div>
 
 
 
(div {})
 
# Text children: You use a string literal
#
 
 
<div>foo</div>
 
 
 
(div {}, 'foo')
 
# Interpolation: You ignore the {} and write the expression as is
#
 
 
<div>{this.state.text}</div>
 
 
 
(div {}, @state.text)
 
# Multiple children: You use the [] notation
#
 
 
<div>
  <b r="">
  <b r="">
</b></b></div>
<b r=""><b r="">
 
 
(div {}, [
  (br {}),
  (br {})
])
 
# Attributes: You write them using {} notation
#
 
 
<div onclick="{this.onClick}"></div>
 
 
 
(div {onClick: @onClick})
</b></b>

Demos

I've re-written all the React front-page examples using CoffeeScript. The translation was really easy.

Hello World

Timer

Todo

Markdown

Using x-tags from Mozilla, we can write custom tags within the DOM. This is a great opportunity to be able to write reusable components without being tied to a particular library. I wrote x-react to have them being rendered in React.

Example

We're first going to write a regular React component.

var Hello = React.createClass({
  render: function() { return <div>{'Hello ' + this.props.name}</div>; }
});

Then, we use xreact.register to bind a React component to a custom tag name.

xreact.register('x-hello', Hello);

At this point, any DOM element will be rendered using React.

<x-hello name="World"></x-hello>

The rendered DOM tree lives in the shadow DOM. This lets us manipulate both the component as well as the rendered <div> using Web Inspector.

Anytime you modify the component, whether it is in the inspector or in Javascript with the regular DOM API, React is going to be invoked to update the rendered version.

Behind the scenes

When you call xreact.register, we call xtag.register saying that whenever an DOM element is created, we render a special component called XReact in the shadow root of <x-hello>.

xtag.register('x-hello', {
  lifecycle: {
    created: function() {
      React.renderComponent(
        XReact({element: this}),
        this.createShadowRoot()
      );
    }
  }
});

XReact is a really simple component that takes a DOM node, in this case <x-hello name="World" /> and converts it to the React equivalent: Hello({name: 'World'}).

var XReact = React.createClass({
  render: function() {
    return convertDOMToReact(this.props.element);
  }

MutationObserver gives us a callback whenever the DOM element is changed. We just have to call this.forceUpdate() to make sure the React rendered version stays in sync.

  componentDidMount: function() {
    new MutationObserver(this.forceUpdate.bind(this)).observe(
      this.props.element, {/* all the possible mutations */}
    );
  }
);

That's it 🙂

Conclusion

It was really easy to make this small bridge in order to be able to create custom tags and have them rendered using React. Unfortunately, this experiment is only working on Chrome as it is relying on MutationObserver and Shadow DOM.