我知道在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
如果可能的话,那就是“榆树在底”'模式优越?试图解释为什么似乎没有关于它的文献和&这是一个可能的解释。
答案 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.encode
和JSON.parse
有点贵,因为你必须从Elm获取数据并使用可消费的JS格式组件),但假设ThatComponent
对象上有React
,ReactDOM
和window
,您可以尝试使用
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()));
});