-
Notifications
You must be signed in to change notification settings - Fork 356
Description
I discovered a race condition that prevents future reconciling from occurring. I've submitted a PR GH-863 with a devcards test and a fix.
Explanation
Right now, this block of code can result in a race condition that can stop future reconciling from occurring. Block of code inlined next for convenience:
([resp query remote]
(when-not (nil? remote)
(p/queue! this (keys resp) remote))
(merge! this resp query remote)
(p/reconcile! this remote))))))))In particular, (merge! ...) will cause a state change that can trigger a (schedule-render! ...) and therefore eventually a reconcile. In cases where the requestAnimationFrame immediately runs the scheduled reconcile, "eventually" becomes "immediately." During this immediate reconcile, the following line will set :queued to false:
(swap! state update-in [:queued] not)In this scenario, the last(p/reconcile! this remote) in the code block above will run right after the reconcile triggered by requestAnimationFrame. This reconcile will also call the following line:
(swap! state update-in [:queued] not)which will set :queued back to true, without adding enqueueing anything to :queue-remote or :queue.
This puts our reconciler into a state in which subsequent calls to schedule-render! will think that there is already a render scheduled and won't queue a render and reconcile.
(defn schedule-render! [reconciler]
(when (p/schedule-render! reconciler)
(queue-render! #(p/reconcile! reconciler))))where p/schedule-render! is defined as follows:
(schedule-render! [_]
(if-not (:queued @state)
(do
(swap! state assoc :queued true)
true)
false))This means that any reconciles that would result from a change in our reconciler :state won't trigger a reconcile. See here:
(add-watch (:state config) (or target guid)
(fn [_ _ _ _]
(swap! state update-in [:t] inc)
#?(:cljs
(if-not (iquery? root-class)
(queue-render! parsef)
(schedule-render! this)))))And the symptom will be observed state changes not re-rendering our ui.