Skip to content

Functional components forget their watched atoms in strict mode #634

@matej-ibis-ai

Description

@matej-ibis-ai

Running with React strict mode (enabled at the top-level component), React effects are cycled one extra time, which causes functional components created using reagent.impl.component.functional-render to dispose of their watched values, and not watch them anymore.

The effect defined in functional-render should provide a symmetrical action to ratom/dispose! in its first part, in the mount function.

In my preliminary tests, I have extended the Reaction type for the following two methods:

(_snapshot [_this]
  [state watching auto-run])
                                                      
(_restore [this [s w a]]
  (set! watching w)
  (set! state s)
  (set! auto-run a)
  (set! dirty? true)
  (doseq [watcher (set w)]
    (-add-watch watcher this handle-reaction-change)))

and used them to save the related values of the Reaction in a new Javascript field between the cleanup and second run of the effect, like this:

(react/useEffect
 (fn mount []
   (when-some [reagent-state (.-current state-ref)]
     (when-some [r-argv (gobj/get reagent-state "ratomSnapshot" nil)]
       (let [rat (gobj/get reagent-state "cljsRatom")]
         (._restore rat r-argv)
         (gobj/remove reagent-state "ratomSnapshot"))))
   (fn unmount []
     (when-some [rat ^ratom/Reaction (gobj/get reagent-state "cljsRatom")]
       (gobj/set reagent-state "ratomSnapshot" (._snapshot rat)))
     (some-> (gobj/get reagent-state "cljsRatom") ratom/dispose!)
     ))
 ;; Ignore props - only run effect once on mount and unmount
 ;; (which means always twice under the React strict mode).
 #js [])

That solved the issue I have described here, although I still see failures in expanding seqs rendered by these functional components -- but I will be filing that as a separate issue when I gain more understanding of what's going wrong there.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions