Created
September 2, 2016 12:08
-
-
Save niwinz/986756f653eb540e66f118e982249663 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(require '[lentes.core :as l]) | |
;; Lets define a simple lense that compoes: | |
;; - a lense that focuses to the (get-in [:foo :bar] ...) on the data struct | |
;; - a lense that just applies the inc transformation | |
;; This is in some mode analogous to: #(inc (get-in % [:foo :bar])) | |
;; but generalized as a composable lense. | |
(def my-lens | |
(comp (l/in [:foo :bar]) | |
(l/units inc dec))) | |
;; Define the state atom, that holds the main state | |
(def my-state (atom {:foo {:bar 1}})) | |
;; Define a derived atom with the previously defined lense | |
(def my-ref (l/derive my-lens my-state)) | |
;; Let see a something like repl session for understand how it works: | |
@my-ref | |
;; => 2 | |
;; in the moment of deref, the my-lens is applied to the state of | |
;; the original state and the computed value is returned, if you | |
;; deref it again, the same operation will be performed. | |
(swap! my-state update-in [:foo :bar] inc) | |
;; In this step only the swap! is performed, no more data is calculated | |
;; the derived lense does nothing, because it only computes the result | |
;; on the deref. So you can have as many top level derived atoms with | |
;; lenses without worrying about performance on modifying the state atom. | |
@my-ref | |
;; => 3 | |
;; Again, on this op, the lense is applied to the original state value | |
;; and the computed value is returned | |
@my-state | |
;; => {:foo {:bar 2}} | |
(swap! my-ref inc) | |
;; In this step, the backward operation is applied and the original atom | |
;; is transformed applying a transformation only to the derived atom "vision" | |
;; of the original atom. | |
@my-state | |
;; => {:foo {:bar 3}} | |
@my-ref | |
;; => 4 | |
;; Now, you use this together with rum and its reactive mixin: | |
(rum/defc my-component < rum/reactive | |
[] | |
(let [value (rum/react my-ref)] | |
[:span value])) | |
;; When this component is mounted, a watcher is hold on the my-ref derived | |
;; atom. Having this component mounted, let see how different operations | |
;; can cause or not rerenders: | |
(swap! my-state update-in [:foo :bar] inc) | |
;; This will cause a rerender on the component because the derived atom is | |
;; directly affected by the change. | |
(swap! my-state assoc :baz :somevalue) | |
;; This operation will modify the main state, but the commponent will | |
;; remain unchanged and no rerender is triggered. Because the watchers | |
;; attached to the refs does not triggers its watchers if the value is | |
;; not changed. | |
;; And as I have said previously, if you have more atoms derived from the same | |
;; state, no additional overhead is done for that refs. The transformation | |
;; is only applied when you are derefing the derived atom with `rum/react` | |
;; and when original atom changes for check if the derived value is changed. | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment