Sé que el uso de componentes Elm ("módulos"? Todavía está aprendiendo lenguaje) dentro de React es un patrón establecido con bibliotecas como react-elm-components, pero ¿hay alguna manera de hacer lo inverso?

Por ejemplo, algo como esto es posible:

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

Pero qué hay de esto:

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

Si es posible, ¿es superior el patrón 'elm en el fondo'? Intentar razonar por qué no parece haber literatura al respecto y esa es una posible explicación.

10
Brandon 28 dic. 2016 a las 21:00

3 respuestas

La mejor respuesta

Como se señaló, esto no funciona como está debido a onload, pero puede ayudar a alguien más a buscar algo similar

Siempre puede representar un componente Reaccionar, hasta que pueda reescribirlo;) dentro de un nodo Elm. El truco va a ser montarlo. Disparos desde la cadera: sería un poco hacky (y un poco caro con un Json.Encode.encode y JSON.parse ya que tienes que sacar los datos de Elm y ponerlos en un formato JS consumible para el componente) , pero suponiendo que tenga ThatComponent, React y ReactDOM en el objeto window, puede intentar algo similar a

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 ] []

Sin embargo, lo que tendrá es un problema con el mantenimiento de su propio estado, que obviamente es malo y va en contra de la arquitectura Elm (pero probablemente lo sepa y quiera reutilizar algo preconstruido). Puede usar los puertos para enviar datos nuevamente, pero le gustaría incluir ese reactComponent en Html.Lazy.lazy3 para que no se vuelva a generar (por lo que enviaría tanto el codificador como datos por separado).

4
toastal 18 ene. 2018 a las 09:45

No hagas eso. Todo el punto de Elm es el diseño hexagonal. Elm está destinado a funcionar como un sistema cerrado, uno en el que los males de JS no pueden penetrar. Es por eso que incrustar Elm en JS es de primera clase, y tiene tantos problemas para encontrar el inverso. La idea de incorporar React en Elm es entregar el valor del determinismo y las garantías de Elm. Es mejor que no uses Elm en absoluto.

Si realmente solo desea hacer una programación funcional en el navegador y usar componentes React con la arquitectura Elm, consulte PureScript PUX. PUX está diseñado para ese caso de uso y le dará mejores resultados que hackear a Elm para hacer cosas que Elm fue específicamente diseñado para prevenir.

Si mis comentarios no son para ti, puedo ofrecerte los siguientes consejos para ser malo de esta manera, sin ser demasiado malo.

Primero, puede lograr esto con ports. Escriba su aplicación Elm para disparar eventos en un puerto a JavaScript cuando desee representar su componente de reacción. Luego renderice el componente de reacción dentro del espacio Elm Dom, de la manera estándar con JavaScript.

En segundo lugar (esto es lo más cercano a hacerlo correctamente), puede escribir esto utilizando los módulos Elm Native. Esto requerirá que aprenda el tiempo de ejecución indocumentado de Elm y que escriba código que interactúe con él. Lo que harás es escribir un elemento Html personalizado en el sistema de bajo nivel de Elm, que represente React dentro de sí mismo y gestione la renderización.

¡Buena suerte!

9
Fresheyeball 28 dic. 2016 a las 20:23

He estado tratando de hacer lo mismo. Tomé un popular selector de fecha de React y comencé a interoperar a través de los puertos. Todavía está en progreso pero funciona

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;

Entonces mi código de puertos se ve como

import datepicker from './reactDPPort.jsx';
elm.ports.trigger.subscribe( (s) => {
    datepicker(s, res => app.ports.toElm.send(res.toString()));
});
1
Simon H 22 sep. 2017 a las 14:37