Clojure のデータ構造はすべて永続的ですが、あなたの例では副作用が必要なようです (つまり、DOM をその場で叩いて変更します)。
これはかなり手続き的/命令的なアプローチであるため、一歩下がって問題をより機能的なスタイルに再構成する価値があるかもしれません。私の個人的な哲学は、「ビューをデータとして」扱い、Clojure の永続的なデータ構造を使用してレンダリングする必要がある最後の瞬間までモデル化することです。
ヒックをご存知ですか?アイデアは、プレーンなベクターとマップを使用して HTML または SVG DOM を表すことです。
[:div {:with "attribute"} "and" [:span "children"]]
単純な古い Clojure 関数を構成することで構築できます。Clojure では、(元の Hiccup ライブラリを使用して) これを HTML にレンダリングできますが、(潜在的に存在する) DOM 構造に直接レンダリングする ClojureScript ライブラリが少なくとも 2 つあります。
Crateは Hiccup の移植版であり、Singultには D3.js にインスパイアされたデータ バインディングのような追加のセマンティクスがあります (Singult は実際には CoffeeScript で記述されているため、プレーンな JavaScript から使用でき、Crate よりも高速です)。
私のC2ライブラリは、Singult の上にデータ バインディング セマンティクスを構築して、DOM を基になるデータと同期させます。TODO リストの次のテンプレートを検討してください。
(bind! "#main"
[:section#main {:style {:display (when (zero? (core/todo-count)) "none")}}
[:input#toggle-all {:type "checkbox"
:properties {:checked (every? :completed? @core/!todos)}}]
[:label {:for "toggle-all"} "Mark all as complete"]
[:ul#todo-list (unify (case @core/!filter
:active (remove :completed? @core/!todos)
:completed (filter :completed? @core/!todos)
;;default to showing all events
@core/!todos)
todo*)]])
( C2 TodoMVC 実装から取得)。「すべてチェック」ボックスがチェックされているかどうかなどは、基礎となるデータ (アトムに格納されている) から直接導出されます。そのデータが変更されるたびに、テンプレートが再実行され、dom が自動的に更新されます。
基本的な考え方は、アプリケーション データから Hiccup データ構造への順方向のマッピングを構築し、ライブラリに DOM の同期 (子、属性の追加/削除など) を任せることです。DOM の状態を気にする必要がない場合 (これは既に追加されていますか? クラスをトグルする必要がありますか?)、多くの付随的な複雑さがなくなります。