You pretty much have it. React is a better match with the Clojure programming model.
Pulling your application state completely out of the DOM is the key win and everything else is incremental gains/taste.
Since I care about this a lot I'll write more stuff:
Consider the basic conceptual model of Backbone. Your model changes, you get an event, you run your model object and matching template through your template engine, you get an HTML string and innerHTML it into the right place in the DOM. It's a simple functional transform of data into DOM in response to an event and the simplicity is a large part of the initial appeal of Backbone.
The issue with the event->model+template->innerHTML sequence is what I call the idempotent update problem. The transform from model into the DOM is idempotent and as long as your model and template are the same the resulting DOM subtree will be identical. This is a problem because identical means blowing away all the state that was previously in the DOM subtree: event handlers, form fields, subcomponents, widgets from other libraries, etc. In small apps, this isn't a problem you just event delegate the listeners, be careful around your forms and widgets and you're fine. The problem is that when your app gets big enough you want to split it into components so you stay sane and once you do that you invariably want to nest your components and the idempotent update problem bites you hard. There are workarounds and people manage but you lose the conceptual simplicity of the Backbone model almost immediately.
The benefit of the virtual DOM/diffing approach is that it lets you retain the simplicity of the idempotent transform of model to DOM while solving the idempotent update problem. Of course, with React you have the issue of getting things back from the DOM to your model that two way bindings give you but two way bindings are incompatible with the Clojure model.
Angular templating system and bindings deliver the same benefits and it remains my preferred javascript solution to the problem. Other people complain about the introduction of a lot of extra things you need to know (scopes, change propagation, directive phases, digest cycle), how things can interact strangely (directives and repeats), and that the system is monolithic (providers, DI, promises). These are legitimate complaints but I've been interested in this problem for years and I have yet to find a system that doesn't have legitimate complaints and angular is roughly equal in complexity to anything I've found that covers the same ground.
The counter shows the portion of the application state you're tracking while the contents of the textarea show the part you're not. It's obviously stupid but the contents of the textbox are an easily visible way of allowing you to mutate the DOM (other mutations could be attached event listeners, instantiated jQuery UI widgets, etc) and see it undone.
I'll add that even if it seems like you can track all the state (e.g. add a textarea field to the model and set a keyup or blur to save the contents for re-render) that's a disaster. If you're typing in the middle of the textarea the cursor position isn't remembered. You can store that too but what if you resize the text field? The list of edge cases is endless. You really want to bypass it by using something that updates the DOM intelligently.
Pulling your application state completely out of the DOM is the key win and everything else is incremental gains/taste.
Since I care about this a lot I'll write more stuff:
Consider the basic conceptual model of Backbone. Your model changes, you get an event, you run your model object and matching template through your template engine, you get an HTML string and innerHTML it into the right place in the DOM. It's a simple functional transform of data into DOM in response to an event and the simplicity is a large part of the initial appeal of Backbone.
The issue with the event->model+template->innerHTML sequence is what I call the idempotent update problem. The transform from model into the DOM is idempotent and as long as your model and template are the same the resulting DOM subtree will be identical. This is a problem because identical means blowing away all the state that was previously in the DOM subtree: event handlers, form fields, subcomponents, widgets from other libraries, etc. In small apps, this isn't a problem you just event delegate the listeners, be careful around your forms and widgets and you're fine. The problem is that when your app gets big enough you want to split it into components so you stay sane and once you do that you invariably want to nest your components and the idempotent update problem bites you hard. There are workarounds and people manage but you lose the conceptual simplicity of the Backbone model almost immediately.
The benefit of the virtual DOM/diffing approach is that it lets you retain the simplicity of the idempotent transform of model to DOM while solving the idempotent update problem. Of course, with React you have the issue of getting things back from the DOM to your model that two way bindings give you but two way bindings are incompatible with the Clojure model.
Angular templating system and bindings deliver the same benefits and it remains my preferred javascript solution to the problem. Other people complain about the introduction of a lot of extra things you need to know (scopes, change propagation, directive phases, digest cycle), how things can interact strangely (directives and repeats), and that the system is monolithic (providers, DI, promises). These are legitimate complaints but I've been interested in this problem for years and I have yet to find a system that doesn't have legitimate complaints and angular is roughly equal in complexity to anything I've found that covers the same ground.