Last active
May 4, 2018 20:52
-
-
Save joefiorini/4372e2362e658d3092419e708416f92c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class MountableWatcher extends HTMLElement { | |
constructor() { | |
console.log("creating component"); | |
super(); | |
} | |
connectedCallback() { | |
this.render(); | |
} | |
disconnectedCallback() { | |
console.log("disconnected"); | |
this.dispatchEvent(new CustomEvent("unmounted", { bubbles: false })); | |
} | |
attributeChangedCallback(attrName, oldVal, newVal) { | |
if (attrName === "onunmount" && oldVal !== newVal) { | |
if (newVal === null) { | |
this.onunmount = null; | |
} else { | |
} | |
} | |
} | |
static get observedAttributes() { | |
return ["onunmount"]; | |
} | |
get onunmount() { | |
return this._onUnmountFn; | |
} | |
set onunmount(handler) { | |
if (this._onUnmountFn) { | |
this.removeEventListener("unmount", this._onCheckFn); | |
this._onUnmountFn = null; | |
} | |
if (typeof handler === "function") { | |
this._onUnmountFn = handler; | |
this.addEventListener("unmount", this._onCheckFn); | |
} | |
} | |
render() { | |
this.innerHTML = "<p>Hello from watcher</p>"; | |
} | |
} | |
customElements.define("mountable-watcher", MountableWatcher); | |
// React Elm Component | |
var ElmComponent = React.createClass({ | |
initialize: function(node) { | |
if (node === null) return; | |
var app = this.props.src.embed(node, this.props.flags); | |
if (typeof this.props.ports !== "undefined") { | |
this.props.ports(app.ports); | |
} | |
}, | |
shouldComponentUpdate: function(prevProps) { | |
return false; | |
}, | |
render: function() { | |
return React.createElement("div", { ref: this.initialize }); | |
} | |
}); | |
var node = document.getElementById("elm-app"); | |
function remount(el) { | |
ReactDOM.unmountComponentAtNode(el); | |
ReactDOM.render(React.createElement(ElmComponent, { src: Elm.Main }), el); | |
} | |
document.getElementById("button").addEventListener("click", function() { | |
remount(node); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<script src="https://unpkg.com/[email protected]/dist/react.min.js"></script> | |
<script src="https://unpkg.com/[email protected]/dist/react-dom.min.js"></script> | |
<style> | |
html { | |
background: #F7F7F7; | |
} | |
#elm-app { | |
color: red; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="elm-app"></div> | |
<label> | |
Click this button and watch the handlers leak on the console. Each time the button is clicked, the React component remounts | |
and adds a new handler and does not clean up old ones. | |
<button id="button">remount</button> | |
</label> | |
<script src="/component.js"></script> | |
<script src="/_compile/Main.elm"></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Main exposing (..) | |
import Html exposing (Html, program, text) | |
import MountableProgram as Mountable exposing (Mountable, mountableProgram) | |
import Time | |
type alias Model = | |
() | |
type Msg | |
= Tick Time.Time | |
main : Program Never (Mountable Model) (Mountable.Msg Msg) | |
main = | |
mountableProgram | |
{ init = init | |
, view = \_ -> text "Hello, I am leaking." | |
, update = update | |
, subscriptions = \_ -> Time.every (2 * Time.second) Tick | |
} | |
init : ( (), Cmd msg ) | |
init = | |
() ! [] | |
getSeconds : a -> String | |
getSeconds = | |
toString >> String.slice 0 -3 | |
update : Msg -> a -> ( a, Cmd Msg ) | |
update msg model = | |
case msg of | |
Tick time -> | |
let | |
_ = | |
Debug.log "tick" (getSeconds time) | |
in | |
model ! [] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module MountableProgram exposing (Mountable, Msg, mountableProgram) | |
import Html exposing (Html, program) | |
import Html.Events exposing (on) | |
import Json.Decode as Decode | |
type alias Mountable a = | |
{ model : a | |
, isMounted : Bool | |
} | |
type Msg msg | |
= Unmounted | |
| AppMsg msg | |
mountableProgram : | |
{ init : ( model, Cmd msg ) | |
, update : msg -> model -> ( model, Cmd msg ) | |
, view : model -> Html msg | |
, subscriptions : model -> Sub msg | |
} | |
-> Program Never (Mountable model) (Msg msg) | |
mountableProgram stuff = | |
let | |
init = | |
let | |
( model, cmd ) = | |
stuff.init | |
in | |
( { model = model, isMounted = True }, Cmd.map AppMsg cmd ) | |
update msg model = | |
case msg of | |
Unmounted -> | |
Debug.log "unmounted" { model | isMounted = False } ! [] | |
AppMsg msg -> | |
let | |
( newModel, cmd ) = | |
stuff.update msg model.model | |
in | |
( { model = newModel, isMounted = model.isMounted }, Cmd.map AppMsg cmd ) | |
view model = | |
Html.section [] [ Html.node "mountable-watcher" [ on "unmounted" (Decode.succeed Unmounted) ] [], Html.map AppMsg (stuff.view model.model) ] | |
subscriptions model = | |
Sub.batch | |
[ if model.isMounted then | |
Sub.map AppMsg (stuff.subscriptions model.model) | |
else | |
Sub.none | |
] | |
in | |
program | |
{ init = init | |
, update = update | |
, view = view | |
, subscriptions = subscriptions | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment