Skip to content

component states

jiyinyiyong edited this page Mar 21, 2020 · 8 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.

Clone this wiki locally