如何通过端口交互来协调渲染(Elm 0.17) [英] How to coordinate rendering with port interactions (Elm 0.17)
问题描述
我想将Elm与Javascript库集成在一起,以使Elm动态创建单元(html div),并且Javascript将带有其id-s并用于执行自定义操作。我想要的顺序是
I would like to integrate Elm with a Javascript library in such a way that Elm would dynamically create "cells" (html divs), and Javascript would be provided with their id-s and use them to perform custom operations. The sequence I want to have is
- Elm创建一个单元格(并分配ID)
- 消息ID为id的邮件发送到端口
- Javascript接收消息并执行其操作
我在一开始就实现了这一目标(完整源代码):
This is how I implemented this at the beginning (full source):
port onCellAdded : CellID -> Cmd msg
update : Msg -> Model -> (Model, Cmd Msg)
update message ({cells} as model) =
case message of
Push ->
let
uid = List.length cells
in
({ model
| cells = [uid] ++ cells
}, onCellAdded uid)
问题是另一侧的
var container = document.getElementById('app');
var demoApp = Elm.RenderDemo.embed(container);
demoApp.ports.onCellAdded.subscribe(function(cellID) {
if(document.getElementById('cell:' + cellID) === null) { window.alert("Cannot find cell " + cellID) }
});
表示找不到此类ID。显然还没有渲染视图。
complained that such id cannot be found. Clearly the view hasn't been rendered yet.
所以我向Elm应用程序添加了另一个状态( OnCellAdded
) ,希望流程如下:
So I added another state (OnCellAdded
) to the Elm application, hoping that the flow would be like this:
- Elm创建一个单元格(在Push上)并请求(
Task .perform
)异步任务OnCellAdded
- 此处呈现视图
-
OnCellAdded
被调用,带有id的消息被发送到端口 - Javascript接收到该消息并执行其操作 >
- Elm creates a cell (on Push) and requests (
Task.perform
) an asynchronous taskOnCellAdded
- Here the view gets rendered
OnCellAdded
gets called and message with id gets sent to port- Javascript receives the message and performs its action
The implementation looked like this (diff) (full source):
update message ({cells} as model) =
case message of
Push ->
let
uid = List.length cells
in
({ model
| cells = [uid] ++ cells
}, msgToCmd (OnCellAdded uid))
OnCellAdded counter ->
(model, onCellAdded counter)
msgToCmd : msg -> Cmd msg
msgToCmd msg =
Task.perform identity identity (Task.succeed msg)
但是在 Push
之后,仍会立即处理 OnCellAdded
,而不会在模型之间进行渲染。
But still OnCellAdded
gets processed right after Push
without the model being rendered in-between.
我最后一次尝试是使用 Update.andThen
(差异)(完整源代码)
My last attempt was using Update.andThen
(diff) (full source)
Push ->
let
uid = List.length cells
in
({ model
| cells = [uid] ++ cells
}, Cmd.none)
|> Update.andThen update (OnCellAdded uid)
仍然无效。在这里我需要一些帮助。
Still it doesn't work. I need some help here.
推荐答案
自 0.17.1
起,
我可以推荐的最简单的方法是使用 setTimeout 等待至少 60ms 或等到下一个 requestAnimationFrame
The easiest I could recommend is using setTimeout to wait at least 60ms or wait until the next requestAnimationFrame
请考虑以下示例:
demoApp.ports.onCellAdded.subscribe(function(cellID) {
setTimeout(function() {
if(document.getElementById('cell:' + cellID) === null) {
window.alert("Cannot find cell " + cellID)
}
}, 60);
});
有一个功能请求#19 添加一个钩子,因此可以知道HTML节点何时在DOM中。
There is a feature request #19 to add a hook, so it is possible to know when the HTML Node is in the DOM.
您可以在此处进行进度在即将发布的版本中。
You can the progress here, most likely it will be in the upcoming releases.
这篇关于如何通过端口交互来协调渲染(Elm 0.17)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!