|
116 | 116 | (binding [*current-component* c] |
117 | 117 | (wrap-render c compiler))) |
118 | 118 |
|
| 119 | +;; Ratom cleanup |
| 120 | +;; On StrictMode React calls mount->unmount->mount on component initialization. |
| 121 | +;; This means we need to use tricks to keep the render ratom running even |
| 122 | +;; though unmount is called on initialization. It we let the dispose to be |
| 123 | +;; called, we lose the ratom watches from derefs inside reagent-render, and |
| 124 | +;; there is no good way to restore them. |
| 125 | + |
| 126 | +(defn cancel-cleanup [^clj component-state] |
| 127 | + (when (.-cleanup-queued component-state) |
| 128 | + (set! (.-cleanup-cancelled component-state) true) |
| 129 | + (set! (.-cleanup-queued component-state) false))) |
| 130 | + |
| 131 | +;; Delay ratom dispose call so it can be cancelled if mount/setup is second time. |
| 132 | +(defn queue-cleanup [^clj component-state] |
| 133 | + (set! (.-cleanup-cancelled component-state) false) |
| 134 | + (set! (.-cleanup-queued component-state) true) |
| 135 | + ;; Promise.resolve creates a microtask, vs setTimeout regular task. |
| 136 | + ;; A scheduled microtask runs before the next event loop begings (where a regular task would run). |
| 137 | + (.then (.resolve js/Promise nil) |
| 138 | + (fn [] |
| 139 | + (when (false? (.-cleanup-cancelled component-state)) |
| 140 | + (set! (.-cleanup-queued component-state) false) |
| 141 | + (batch/mark-rendered component-state) |
| 142 | + (some-> (gobj/get component-state "cljsRatom") ratom/dispose!))))) |
119 | 143 |
|
120 | 144 | ;;; Method wrapping |
121 | 145 |
|
|
193 | 217 |
|
194 | 218 | :componentDidMount |
195 | 219 | (fn componentDidMount [] |
196 | | - (this-as c (.call f c c))) |
| 220 | + (this-as c |
| 221 | + (cancel-cleanup c) |
| 222 | + (when-not (nil? f) |
| 223 | + (.call f c c)))) |
197 | 224 |
|
198 | 225 | :componentWillUnmount |
199 | 226 | (fn componentWillUnmount [] |
200 | 227 | (this-as c |
201 | | - (some-> (gobj/get c "cljsRatom") ratom/dispose!) |
202 | | - (batch/mark-rendered c) |
| 228 | + (queue-cleanup c) |
203 | 229 | (when-not (nil? f) |
204 | 230 | (.call f c c)))) |
205 | 231 |
|
|
218 | 244 | ;; Though the value is nil here, the wrapper function will be |
219 | 245 | ;; added to class to manage Reagent ratom lifecycle. |
220 | 246 | (def obligatory {:shouldComponentUpdate nil |
| 247 | + :componentDidMount nil |
221 | 248 | :componentWillUnmount nil}) |
222 | 249 |
|
223 | 250 | (def dash-to-method-name (util/memoize-1 util/dash-to-method-name)) |
|
427 | 454 | ;; FIXME: Access cljsRatom using interop forms |
428 | 455 | rat ^ratom/Reaction (gobj/get reagent-state "cljsRatom")] |
429 | 456 |
|
430 | | - ;; Delay ratom dispose call so it can be cancelled if StrictMode |
431 | | - ;; calls setup the second time. |
432 | 457 | (react/useEffect |
433 | 458 | (fn mount [] |
434 | | - (when (.-cleanup-queued reagent-state) |
435 | | - ;; (js/console.log "cancel cleanup") |
436 | | - (set! (.-cleanup-cancelled reagent-state) true) |
437 | | - (set! (.-cleanup-queued reagent-state) false)) |
| 459 | + (cancel-cleanup reagent-state) |
438 | 460 | (fn unmount [] |
439 | | - ;; (js/console.log "queue cleanup") |
440 | | - (set! (.-cleanup-cancelled reagent-state) false) |
441 | | - (set! (.-cleanup-queued reagent-state) true) |
442 | | - ;; Promise.resolve creates a microtask, vs setTimeout regular task. |
443 | | - ;; A scheduled microtask runs before the next event loop begings (where a regular task would run). |
444 | | - (.then (.resolve js/Promise nil) |
445 | | - (fn [] |
446 | | - (when (false? (.-cleanup-cancelled reagent-state)) |
447 | | - ;; (js/console.log "run cleanup") |
448 | | - (set! (.-cleanup-queued reagent-state) false) |
449 | | - (some-> (gobj/get reagent-state "cljsRatom") ratom/dispose!)))))) |
| 461 | + (queue-cleanup reagent-state))) |
450 | 462 | ;; Ignore props - only run effect once on mount and unmount |
451 | 463 | ;; (which means always twice under the React strict mode). |
452 | 464 | #js []) |
|
0 commit comments