如何通过端口交互来协调渲染(Elm 0.17) [英] How to coordinate rendering with port interactions (Elm 0.17)

查看:94
本文介绍了如何通过端口交互来协调渲染(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


  1. Elm创建一个单元格(并分配ID)

  2. 消息ID为id的邮件发送到端口

  3. 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:


  1. Elm创建一个单元格(在Push上)并请求( Task .perform )异步任务 OnCellAdded

  2. 此处呈现视图

  3. OnCellAdded 被调用,带有id的消息被发送到端口

  4. Javascript接收到该消息并执行其操作
  5. >
  1. Elm creates a cell (on Push) and requests (Task.perform) an asynchronous task OnCellAdded
  2. Here the view gets rendered
  3. OnCellAdded gets called and message with id gets sent to port
  4. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆