<blockquote> <p>Any problem in computer science can be solved with another level of indirection. -- David Wheeler</p> </blockquote> <p>The <a href="React">http://facebook.github.io/react/">React library from Facebook makes DOM programming functional by using a Virtual DOM. The Virtual DOM is an <em>indirection mechanism</em> that solves the difficult problem of DOM programming: <strong>how to deal with incremental changes to a stateful tree structure</strong>. By abstracting away the statefulness, the Virtual DOM turns the real DOM into an immediate mode GUI, which is perfect for functional programming. Further, the Virtual DOM provides <strong>the last piece of the Web Frontend Puzzle for ClojureScript</strong>.</p> <p>David Nolen has written up a <a href="short">http://swannodette.github.io/2013/12/17/the-future-of-javascript-mvcs/">short explanation</a> of how the Virtual DOM works, as well as some amazing performance benchmarking of React in a ClojureScript context. His work is important, so you should read it. I'd like to focus a bit more on the expressivity and why <strong>I would use React even if it were not so fast</strong>.</p> <p>One can view MVC frameworks as an attempt to impose some structure on the code that has to interface with the DOM. The bargain they propose is this: <strong>wrap the DOM in View objects</strong>, so that subtrees of DOM nodes are managed by a View object. <strong>Wrap your state in Model objects</strong>, which will notify the View objects of changes. You thereby keep a <em>layer of indirection between Models and Views</em>, which inherently need different structure and need to change independently.</p> <p>The layer of indirection (usually an event or observer system) solves a <em>coupling problem</em>. It decouples your state from the DOM, while <strong>leaving you to deal with all of the difficulties of the DOM</strong>. You are essentially making a new type of DOM that is better suited to your GUI domain than plain HTML, but is still a PITA. It is little more than a coat of paint. <em>The DOM is still stateful.</em></p> <p>React takes a different approach. It provides a level of indirection which solves the actual problem with the DOM--statefulness. The DOM has become a smart canvas. <strong>Paint the whole picture again, but only the different parts get wet.</strong></p> <p>Instead of wrapping the DOM in View objects, you create a Virtual DOM (completely managed by React) which mirrors the real DOM. When the model changes, you generate a new Virtual DOM. The differences are calculated and converted into batch operations to the real DOM. In essence, <strong>React is a function which takes two DOMs and generates a list of DOM operations</strong>, <em>i.e.</em>, <strong>it's referentially transparent</strong>.</p> <p>It's easy to imagine how this changes the game. <strong>You no longer need an initializer to set up the DOM and observers to modify it.</strong> The first Virtual DOM rendering is like the second one, in fact like any other! Your "View", if you want to call it that, is simply a function from state to Virtual DOM nodes. <strong>If the state and DOM nodes are immutable, all the better.</strong> There's less work to know if it has changed.</p> <p>This also means that your Views can be composed functionally. Define a component (as a function) and your subcomponents, and build them up functionally. All of the functional abstraction and refactoring that you're used to is available. If you're doing it right, <strong>your code should get shorter, easier to read, and more fun to maintain</strong>.</p> <p>My (short) experience rewriting a program to use React converted me. It was the only library I have used that actually made DOM programming fun and functional--and dare I say my code now works!</p> <p>Which gets me to my last point, which is that React is the final puzzle piece for ClojureScript web frontend development.</p> <ul> <li>Problem: <strong>Global state management</strong></li> <li><p>Solution: Atoms and persistent data structures</p></li> <li>Problem: <strong>Client-server communication</strong></li> <li><p>Solution: EDN (also solved pretty well by JSON)</p></li> <li>Problem: <strong>Callback hell</strong></li> <li><p>Solution: core.async</p></li> <li>Problem: <strong>Stateful DOM</strong></li> <li><p>Solution: React</p></li> </ul> <p>Any other problems left? I can't think of any. That's something to <a href="discuss">http://www.twitter.com/ericnormand">discuss on Twitter</em></a>.</p> <p>I suggest you try React. <a href="Om">https://github.com/swannodette/om">Om by David Nolen is the most mature React ClojureScript library I know of. It does a bit more than I've described here (Om manages your state tree for you, among other things) and is evolving quickly. I have some code that generates React Virtual DOM using <code>hiccup</code> style with macros (so the work is done at compile time), but other than that, contains only half-baked implementations of what's in Om. If you're interested in the <code>hiccup</code> macros, <em>let me know what you'd use it for and I'll put it on github</em>.</p>
Comments (0)
Sign in to post comments.