Cojurescript Om: handling local state changes in different components

I am creating an om-based form, as subsections can be considered minimized or extended. The viewing status is saved in the local state of the subsection:

  (defn subsection-view [subsection owner]
   (reify
      om / IInitState
      (init-state [this]
         {: collapsed true}))

The problem is that each status of the subview views can be performed in both directions, either with the collapse-expand-all button, or with a separate button displayed for each subkey.

To handle expand-compress-all, there is a global crash status stored in the local state of the form:

  (defn form-view [data owner]
   (reify
     om / IInitState
     (init-state [this]
        {: all-collapsed true})))

Obviously, both on-click event buttons are handled by updating the crash state in a local state.

  (om / update-state! owner: collapsed not)

My question is: how do I know which status was last updated to display the correct view?

Or where is the right place (local state or application state) to maintain the status of the collapse, which can be performed from different triggers at different levels of the component tree?

+5
source share
2 answers

I am a fan of core.async and I would use it using channels. I would like the sections to listen on the Collapse / Expand message, and when that happens, change the local state. Changing the local state will result in a repeated draw. Deploying a single partition only updates the local state of the partition.

+2
source

If you think about time and causality to โ€œdisplay the correct viewโ€, you do not have a React / Om point. You should not make this decision. You just have to bind the display to one state and make sure that part of the state is correct. As stated in the Chaos Rules, core.async is the way to go.

Since the components of the field are already connected to something external (the collapse all button), I would only model collapsed inside the local state of the form / Then I would provide a collapse-ch channel for the fields so that they could link back when they were clicked. Finally, I would set up an event handler in IWillMount to listen for these clicks:

 (def init-state [true true true]) (defn form-view [data owner] (reify om/IInitState (init-state [_] {:collapsed init-state :collapse-ch (chan)}) om/IWillMount (will-mount [_] (let [collapse-ch (om/get-state owner :collapse-ch)] (go (loop [] (let [index (<! collapse-ch)] (om/update-state! owner [:collapsed index] not)) (recur))))) om/IRenderState (render-state [_ {:keys [collapsed collapse-ch]}] (dom/div nil (dom/button #js {:onClick (fn [_] (om/set-state! owner :collapsed init-state))} "Collapse All") (apply dom/div nil (map #(om/build field-view {:collapsed? %1} {:init-state {:index %2 :collapse-ch collapse-ch}}) collapsed (range))))))) 

As for the fields, they just need to put their index on the channel with each click:

 (defn field-view [data owner] (reify om/IRenderState (render-state [_ {:keys [index collapse-ch]}] (dom/button #js {:onClick (fn [_] (go (>! collapse-ch index)))} (if (:collapsed? data) "Collapsed" "Showing"))))) 

In case I missed something, a complete example is here . This seems like a lot, but in my experience, this is the best way to achieve a reasonable separation of problems. There is another similar example in tutorial .

+2
source

Source: https://habr.com/ru/post/1214253/


All Articles