内容简介:事件来源:用户输入、用户点击、定时器、远程调用响应等。事件作为一个数据被投入到类似于事件总线的队列,其数据结构为:
re-frame介绍
re-frame 是一个帮助我们快速开发WEB单页面应用的框架,是一个基于数据驱动的框架。其主要流程是如下的一个永无止境大循环:
dispatch——事件分发
事件来源:用户输入、用户点击、定时器、远程调用响应等。事件作为一个数据被投入到类似于事件总线的队列,其数据结构为:
[event-id event-arg1 event-arg2 ...]
re-frame事件分发函数:
(re-frame.core/dispatch [event-id event-arg1 event-arg2])
event-handler——事件处理
对于分发过来的事件,re-frame会根据事件ID(`event-id)找到注册的事件处理函数,进行处理。event-handler是整个应用的业务核心,re-frame使得事件处理过程变成了一个纯函数(稳定、可测试)。
(defn remove-item "删除元素事件处理" [coeffects event] ;; `coeffects` holds the current state of the world. (let [item-id (second event) ;; extract id from event vector db (:db coeffects)] ;; extract the current application state {:db (dissoc-in db [:items item-id]) :request {:request-id :some-thing}})))) ;; 注册事件处理 (re-frame.core/reg-event-fx ;; a part of the re-frame API :remove-item ;; event id remove-item)
事件处理函数的输入参数: [coeffects event]
-
coeffects:包含了事件处理函数执行时当前"世界"的全部状态,包括
db(应用的本地状态)
以及其他事件处理上下文数据,如当前时间,随机数等...{:db app-state ;; 当前app的状态,re-frame默认设置的 :now 事件执行时的时刻 ;; 需要自定义注册 :random-num 随机数 ;; 需要自定义注册 ... }
- event:事件,参见上述
事件数据结构
。
事件处理函数拿都输入参数中的数据,通过计算之后,输出effects,如:
{:db new-db ;; 更新应用状态的效果 :request request-data ;; 远程调用的效果 :cookie cookie-data ;; 更新cookie的效果 :timer timer-data ;; 启动或关闭定时器的效果 ...}
即用一个数据结构来描述事件处理之后要做的一些"副作用"操作,而不是直接在事件处理函数中调用这些副作用操作,如修改数据库,执行远程调用,修改cookie的值,这样会使得事件处理函数变成非纯函数。
PS:上述结构中,key为effect的ID,标志一类effect。
effects handler——效果处理
re-frame会根据effect id 找到事先注册好的效果处理函数,对效果进行处理。如对于 :db
这个默认的效果,re-frame会用新的db替换旧的db(这是re-frame的默认处理)。对于那些自定义效果,则需要注册自定义处理函数,以远程调用效果request为例:
(defn request-effect-handler "远程调用效果处理函数" [{:keys [event params resp-event] :as request-data}] (case event :query-user-balance ;; 模拟远程调用 (js/setTimeout #(re-frame/dispatch [resp-event 20000]) 5000))) ;; 注册效果处理函数 (re-frame/reg-fx :request ;; effect id request-effect-handler)
效果处理完之后,应用的状态被更新改变。
query——查询应用状态中用于显示的相关数据
应用状态被更新之后,负责显示的视图层会从新的状态中,查找出它展示所需要的数据:
(defn query-fn "定义从应用状态db中查询出所需数据函数" [db] ;; db is current app state (:items db)) ;; not much of a materialised view ;; 注册查询函数 (re-frame/reg-sub :query-items ;; 查询ID :query-id query-fn) ;; 因为clojure中关键字也可以作为函数,所以上面的代码等价于: (re-frame/reg-sub :query-items :items)
view——生成新的视图
视图层根据query-id订阅所需要的数据,然后根据数据生成新的视图:
(defn items-view "定义视图生成函数" [] (let [items (re-frame/subscribe [:query-items])] ;; source items from app state [:div (map item-render @items)])) ;; assume item-render already written
subscribe
函数向应用状态中订阅query-id(:query-items)指定的数据,每当应用状态中这个数据发生改变时,都会重新生成新的视图。
Reagent/React——渲染视图
生成的新的视图会被重新渲染到DOM,展现给用户:
(reagent/render [views/items-view] (.getElementById js/document "app"))
示例Demo1—— re-frame simple template
示例Demo2—— Demo1重构后的版本
为什么重构?
re-frame
re-frame核心设计思想:数据
db
以上所述就是小编给大家介绍的《【Clojure】re-frame for SPA》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Web Anatomy
Robert Hoekman Jr.、Jared Spool / New Riders / 2009-12-11 / USD 39.99
At the start of every web design project, the ongoing struggles reappear. We want to design highly usable and self-evident applications, but we also want to devise innovative, compelling, and exciting......一起来看看 《Web Anatomy》 这本书的介绍吧!