有没有办法在 Elm 中使用 React 组件?
Is there a way to use React Components within Elm?
我知道在 React
中使用 Elm
组件("modules"?仍在学习用语)是 libraries like react-elm-components
的既定模式,但有没有办法做到逆?
例如,这样的事情是可能的:
Top-level React App
-> React layout/component
-> Elm components
但是这个呢:
Top-level Elm App
-> Elm layout/components
-> React components
如果可能,'elm-at-the-bottom' 模式是否更优越?试图解释为什么似乎没有关于它的文献&这是一个可能的解释。
正如所指出的那样,由于 onload
,这不能按原样工作,但可能会帮助其他人寻找类似的东西
您始终可以在 Elm 节点内渲染 React 组件——直到您开始重写它 ;)。诀窍是安装它。从臀部拍摄:它会有点 hacky(并且使用 Json.Encode.encode
和 JSON.parse
有点贵,因为你必须将数据从 Elm 中取出并转换为组件的可消费 JS 格式) ,但假设您在 window
对象上有 ThatComponent
、React
和 ReactDOM
,您可以尝试使用
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
中,这样它就不会重新呈现自身(这就是为什么您要同时发送编码器和数据分开)。
不要那样做。 Elm 的重点是六边形设计。 Elm 旨在作为一个封闭的系统运行,JS 的邪恶无法渗透其中。这就是为什么在 JS 中嵌入 Elm 是第一个 class,你很难找到逆。将 React 嵌入 Elm 的想法是交出 Elm 的确定性和保证的价值。您还不如根本不使用 Elm。
如果您真的只想在浏览器中进行函数式编程并使用 Elm 架构的 React 组件,请查看 PureScript PUX。 PUX 专为该用例而设计,与入侵 Elm 以执行 Elm 专门设计来防止的事情相比,它会给您带来更好的结果。
如果我的评论对你来说是行不通的,我可以提供以下建议,以这种方式变得邪恶,但又不会太邪恶。
首先,您可以使用 ports
完成此操作。当你想渲染你的 React 组件时,编写你的 Elm 应用程序来触发 JavaScript 端口上的事件。然后以 JavaScript.
的标准方式在 Elm Dom space 内渲染反应组件
其次(这是您将要获得的最接近正确执行的方法),您可以使用 Elm Native 模块编写它。这将要求您学习 Elm 的未记录的运行时,并编写与之交互的代码。你要做的是在 Elm 的低级系统中编写一个自定义 Html 元素,它在自身内部渲染 React 并管理重新渲染。
祝你好运!
我一直在尝试做同样的事情。我使用了一个流行的 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()));
});
我知道在 React
中使用 Elm
组件("modules"?仍在学习用语)是 libraries like react-elm-components
的既定模式,但有没有办法做到逆?
例如,这样的事情是可能的:
Top-level React App
-> React layout/component
-> Elm components
但是这个呢:
Top-level Elm App
-> Elm layout/components
-> React components
如果可能,'elm-at-the-bottom' 模式是否更优越?试图解释为什么似乎没有关于它的文献&这是一个可能的解释。
正如所指出的那样,由于 onload
,这不能按原样工作,但可能会帮助其他人寻找类似的东西
您始终可以在 Elm 节点内渲染 React 组件——直到您开始重写它 ;)。诀窍是安装它。从臀部拍摄:它会有点 hacky(并且使用 Json.Encode.encode
和 JSON.parse
有点贵,因为你必须将数据从 Elm 中取出并转换为组件的可消费 JS 格式) ,但假设您在 window
对象上有 ThatComponent
、React
和 ReactDOM
,您可以尝试使用
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
中,这样它就不会重新呈现自身(这就是为什么您要同时发送编码器和数据分开)。
不要那样做。 Elm 的重点是六边形设计。 Elm 旨在作为一个封闭的系统运行,JS 的邪恶无法渗透其中。这就是为什么在 JS 中嵌入 Elm 是第一个 class,你很难找到逆。将 React 嵌入 Elm 的想法是交出 Elm 的确定性和保证的价值。您还不如根本不使用 Elm。
如果您真的只想在浏览器中进行函数式编程并使用 Elm 架构的 React 组件,请查看 PureScript PUX。 PUX 专为该用例而设计,与入侵 Elm 以执行 Elm 专门设计来防止的事情相比,它会给您带来更好的结果。
如果我的评论对你来说是行不通的,我可以提供以下建议,以这种方式变得邪恶,但又不会太邪恶。
首先,您可以使用 ports
完成此操作。当你想渲染你的 React 组件时,编写你的 Elm 应用程序来触发 JavaScript 端口上的事件。然后以 JavaScript.
其次(这是您将要获得的最接近正确执行的方法),您可以使用 Elm Native 模块编写它。这将要求您学习 Elm 的未记录的运行时,并编写与之交互的代码。你要做的是在 Elm 的低级系统中编写一个自定义 Html 元素,它在自身内部渲染 React 并管理重新渲染。
祝你好运!
我一直在尝试做同样的事情。我使用了一个流行的 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()));
});