有没有办法在Elm中使用React组件?

时间:2016-12-28 18:00:44

标签: reactjs elm

我知道在Elm中使用React组件("模块"?仍在学习用语)是libraries like react-elm-components已建立的模式,但有没有办法反过来吗?

例如,这样的事情是可能的:

Top-level React App
 -> React layout/component
    -> Elm components

但是这个怎么样:

Top-level Elm App
  -> Elm layout/components
     -> React components

如果可能的话,那就是“榆树在底”'模式优越?试图解释为什么似乎没有关于它的文献和&这是一个可能的解释。

3 个答案:

答案 0 :(得分:9)

不要那样做。榆树的重点是六边形设计。榆树的目的是作为一个封闭的系统,JS的邪恶无法渗透。这就是为什么在JS中嵌入Elm是一流的,并且你在查找反向时遇到了这样的麻烦。将React嵌入Elm的想法是交出Elm的决定论和保证的价值。你可能根本不使用榆树。

如果您真的只想在浏览器中进行函数式编程并使用带有Elm架构的React组件,请查看PureScript PUX。 PUX专为该用例而设计,并且可以为您提供比黑客榆树更好的结果来做Elm专门设计用来防止的事情。

如果我的评论对你来说不起作用,我可以通过这种方式提出以下建议,而不是太邪恶。

首先,您可以使用ports完成此操作。当您想要渲染您的反应组件时,将您的Elm应用程序编写为将端口上的事件激活到JavaScript。然后使用JavaScript以标准方式渲染Elm Dom空间内的react组件。

第二个(这是你最接近正确的做法),你可以使用Elm Native模块来编写它。这将要求您学习Elm的未记录的运行时,并编写与之交互的代码。你要做的是在Elm的低级系统中编写一个自定义的Html元素,它将React内部渲染并管理重新渲染。

祝你好运!

答案 1 :(得分:4)

正如所指出的,由于onload,这不会按原样运作,但可以帮助其他人寻找类似的东西

你总是可以渲染一个React组件 - 直到你绕过它来重写它;) - 在一个Elm节点内。诀窍是安装它。从臀部拍摄:它有点hacky(Json.Encode.encodeJSON.parse有点贵,因为你必须从Elm获取数据并使用可消费的JS格式组件),但假设ThatComponent对象上有ReactReactDOMwindow,您可以尝试使用

import Html exposing (Html, div)
import Html.Attributes as Attr exposing (attribute)
import Json.Encode as Encode exposing (Value)


reactComponent : String -> (a -> Value) -> a -> Html msg
reactComponent componentName encoder data =
    let
        jsonProps : String
        jsonProps =
            Encode.encode 0 <| encoder data

        -- a script to load the React component on `this` which is
        -- the `div` element in this case.
        onLoad : String
        onLoad =
            String.join ""
                [ "javascript:"
                , "window.ReactDOM.render("
                , "window.React.createElement(window[\""
                , componentName
                , "\"], JSON.parse("
                , jsonProps
                , ")), this)"
                ]
    in
        div [ attribute "onload" onLoad ] []

你将拥有的是它维持自己的状态的问题 - 这显然是坏的并且与Elm架构相反(但你可能知道并且希望重用预先构建的东西)。您可以使用端口重新发送数据,但是您希望将reactComponent包裹在Html.Lazy.lazy3中,这样它就不会重新渲染(这就是为什么你这样做了分别发送编码器和数据)。

答案 2 :(得分:1)

我一直在努力做同样的事情。我采用了一个受欢迎的React日期选择器,并通过端口互操作开始。它仍在进行中,但确实有效

import React from 'react';
import ReactDOM from 'react-dom';

import * as Datetime from 'react-datetime'

function datepicker(d, cb) {
    return requestAnimationFrame( () => {
        ReactDOM.render(Welcome(d, (res) => {
            cb(res);
        }), document.getElementById('reactDate'));            
    });
}

function Welcome(initialdate, cb) {
  return (
      <div>
         <h1>{initialdate}</h1>
         <Datetime onChange={cb} value={initialdate} />
     </div>
  );
}

export default datepicker;

然后我的端口代码看起来像

import datepicker from './reactDPPort.jsx';
elm.ports.trigger.subscribe( (s) => {
    datepicker(s, res => app.ports.toElm.send(res.toString()));
});