component states

ChenYong edited this page Jan 11, 2018 · 6 revisions

Component States

Crossing components states updating is a little confusing in Respo. But I tried to make inner-component states updating to be easier:

(defn on-click [state]
  (fn [e dispatch! mutate!]
    (mutate! (update state :count inc))))

The mutate! function above just updates component state.

cursor->

states is stored globally in store:

(defonce store (atom {:states {}}))

It's represented in tree, I call the paths to each node "cursors". And by getting a cursor, you may know where to update the states. A simple way to specify a sub-cursor is like this:

(cursor-> :sub-cursor comp-demo states p1 p2)

which expands to:

(assoc (comp-demo (:sub-cursor states) p1 p2) :cursor (conj %cursor :sub-cursor))

where %cursor was passed in from the macro defcomp.

mutate!

Currently when you write:

(def initial-state {:count 1})

(defn on-click [state]
  (fn [e dispatch! mutate!]
    (mutate! (update state :count inc))))

(defcomp comp-demo [states]
  (let [state (or (:data states) initial-state)])
  (div {}
    (<> div (str (:count 1)) nil)
    (=< 8 0)
    (button {:inner-text "inc"
             :on-click (on-click state)})))

after macros expanded it becomes:

(def initial-state {:count 1})

(defn on-click [state]
  (fn [e dispatch! mutate!]
    (mutate! (update state :count inc))))

(def comp-demo
  (create-comp
    (fn [states]
      (fn [%cursor]
        (let [state (or (:data states) initial-state)])
        (create-element :div {}
          (div {:inner-text (str (:count 1)), :style nil})
          (comp-space 8 0)
          (button {:inner-text "inc"
                   :on-click (on-click state)}))))))

It looks tedious but you can see %cursor in the code. And we can pass %cursor explicitly to show how it works:

(def initial-state {:count 1})

(defn on-click [%cursor state]
  (fn [e dispatch! mutate!]
    ; (mutate! (update state :count inc))
    (dispatch! :states [%cursor (update state :count inc)])))

(def comp-demo
  (create-comp
    (fn [states]
      (fn [%cursor]
        (let [state (or (:data states) initial-state)])
        (create-element :div {}
          (div {:inner-text (str (:count 1)), :style nil})
          (comp-space 8 0)
          (button {:inner-text "inc"
                   :on-click (on-click %cursor state)}))))))

So mutate! is only a small wrapper based on #(dispatch! :states [%cursor %]). And you can even call (mutate! %cursor s) to pass a specific cursor.

(fn
  ([next-state] (dispatch! :states [this-cursor next-state]))
  ([%cursor next-state] (dispatch! :states [%cursor next-state])))

So if the cursor is passed down from a parent component, then you can update parent states.

You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.