我想知道反应香蕉是如何设计来处理以下情况的:
假设我有一个中央数据结构。用户能够自由地打开和关闭任意数量的不同类型的窗口,这些窗口既显示数据又允许用户对其进行修改。
因此,鉴于这种情况的性质,我认为仅仅尝试创建一个大型网络并不会奏效。这是每个窗口都有一个网络并且以某种方式连接的东西吗?
在像这样的其他情况下,我将数据结构放在每个人都向其发送更新的单个通道后面。然后数据结构将“发布”所有窗口都“收听”的更新(触发事件)。
我想知道反应香蕉是如何设计来处理以下情况的:
假设我有一个中央数据结构。用户能够自由地打开和关闭任意数量的不同类型的窗口,这些窗口既显示数据又允许用户对其进行修改。
因此,鉴于这种情况的性质,我认为仅仅尝试创建一个大型网络并不会奏效。这是每个窗口都有一个网络并且以某种方式连接的东西吗?
在像这样的其他情况下,我将数据结构放在每个人都向其发送更新的单个通道后面。然后数据结构将“发布”所有窗口都“收听”的更新(触发事件)。
我的一个项目中有一个相关问题,它使用类似于 MVC 架构的东西。中心数据结构被称为
-- the data is a tree, and it's kept as a zipper to the current node
Discrete MyDataZip
这是我的控制器声明的精简版本:
data Controller st = Controller {
dState :: Discrete st
,eUpdateZip :: Event (MyDataZip -> MyDataZip)
,eResponse :: Event (IO ())
,bDiagChange :: Behavior (Diagram Cairo R2 -> Diagram Cairo R2)
}
构造时,大多数控制器都会获得对 的引用dZip :: Discrete MyDataZip
,但无法直接修改它。控制器指定更新的唯一方法是通过eUpdateZip
控制器数据结构中的流。
多个控制器被组装成一个图形,它只是一个放置在存在类型包装器中的控制器列表data EControl = forall st. EControl (Controller st)
。我只是mconcat
将所有单独的eUpdateZip
参数获取到一个Event (MyDataZip -> MyDataZip)
用于创建Discrete MyDataZip
. 整个事情都有效,因为创建新控制器是纯粹的,所以它可以在同一个 let-binding 中完成,允许递归引用。
打开新窗口和其他 IO 任务都是在eResponse
流中完成的,类似mconcat
d 然后传递给reactimate
.
您可以查看darcs 存储库以获取更多详细信息,请查看“src/Jaek/UI/Controllers/”和“src/Jaek/UI/ControlGraph.hs”。
编辑:核心问题是一个大型网络对于开发人员的 POV 来说相当笨拙。您可以通过分割网络来降低复杂性,这是一个很好的解决方案。在我的设计中,我通过使响应式参与者符合特定的控制器模型,并为这些模型交互创建明确定义的方式,为网络引入了许多结构。由于我的控制器是持久的,所有这些都是静态设置的,但它可以动态完成,在这种情况下,我可能会让控制器管理器在一个线程中运行,并且生成新控制器的操作(例如打开一个新窗口)会发送一个向线程发送消息以创建新控制器。
目前,无法在事件网络编译后向事件网络添加或删除外部事件(从反应香蕉版本 0.4.3 开始)。换句话说,不可能在单个事件网络中描述您的任务。但是,您可以利用外部事件或多个事件网络,这会导致如下解决方案:
AddHandler
事物)。IORef
)。(这可能是最不令人满意的解决方案。)