Question:
Let Pt2Int.t = { x: int; y : int }
. Suppoose we want to implement a reactive
variable for the global window size.
As far as I can tell, this requires the use of Bonsai.Edge:
Is this the correct way to implement Pt2Int.t Bonsai.Computation.t
module Action = struct
type t = Set_size of { size : Pt2Int.t } [@@deriving sexp, equal]
end
module Model = struct
type t = { size : Pt2Int.t } [@@deriving sexp, equal]
let apply (_model : t) (action : Action.t) : t =
match action with
| Set_size s -> { size = s.size }
let get_window_size () : Pt2Int.t = Pt2Int.{ x = Dom_html.window##.innerWidth; y = Dom_html.window##.innerHeight }
end
module type Global_Window_Size = sig
type t [@@deriving sexp, equal]
end
type t = { model : Model.t; inject : Action.t list -> unit Effect.t }
So far, this is all pretty boring. We implement the Model.t which stores the size,
and the only valid Action is setting the size.
let register_onresize inject =
Firebug.console##log "registering Global_Window_Size: changed / resize";
Dom_html.window##.onresize :=
Dom_html.handler (fun _ ->
Firebug.console##log "Global_Window_Size: changed / resize";
let _ =
Vdom.Effect.Expert.handle_non_dom_event_exn
@@ inject [ Action.(Set_size { size = Model.get_window_size () }) ]
in
Js.bool false)
This is the function we call to setup the onresize handler.
The onresize handler injects the Action.Set_size .
let window_inner_size : t Bonsai.Computation.t =
let%sub model, inject =
Bonsai.state_machine0 [%here]
(module Model)
(module struct
type t = Action.t list [@@deriving sexp, equal]
end)
~default_model:Model.{ size = Model.get_window_size () }
~apply_action:(fun ~inject:_ ~schedule_event:_ model actions -> List.fold actions ~init:model ~f:Model.apply)
in
let on_activate : unit Effect.t Value.t =
let%map inject = inject in
register_onresize inject ;
Effect.return @@ Firebug.console##log "on activate Global_Window_Size: changed / resize" in
let on_deactivate : unit Effect.t Value.t =
let%map _ = inject in
Effect.return @@ Firebug.console##log "on deactivate Global_Window_Size: changed / resize" in
let%sub _ = Bonsai.Edge.lifecycle ~on_deactivate ~on_activate () in
let%arr model = model and inject = inject in
{ model; inject }
This is where things get realy iffy for me. In an execution of the program, I get:
on deactivate Global_Window_Size: changed / resize
registering Global_Window_Size: changed / resize
on activate Global_Window_Size: changed / resize
Why is “on deactivate” running at all? Why does it run before “on activate” ?
This I struggle with.
Another problem I have with this is: how do ensure that “on activate” only runs once ?
I am afraid that if initialize this multiple times, only the last one gets the updates.
Question: What is the correct way to implement a Pt2Int.t Value.t
for keeping track
of the window size?
Thanks!