Upgrade to Pro — share decks privately, control downloads, hide ads and more …

React inside Elm

sporto
September 15, 2017

React inside Elm

This presentation shows how we are embedding React inside Elm

sporto

September 15, 2017
Tweet

More Decks by sporto

Other Decks in Technology

Transcript

  1. R E A C T I N S I D

    E E L M S E B A S T I A N P O R T O
  2. 2 Y E A R S A G O S

    TA R T E D W I T H R E A C T
  3. W H AT W E WA N T E L

    M E V E RY W H E R E
  4. B U T T H AT I S N O

    T H A P P E N I N G
  5. S E C O N D B E S T

    T H I N G Foundations in ELM Legacy widgets in React
  6. W E B C O M P O N E

    N T S E L M A N D W E B C O M P O N E N T S - R I C H A R D F E L D M A N H T T P S : / / W W W. Y O U T U B E . C O M / WAT C H ? V = A R 3 TA K W E 8 O 0
  7. W E B C O M P O N E

    N T S - Shadow DOM - Html imports - Custom elements
  8. C U S T O M E L E M

    E N T S <x-widget count="1" />
  9. W H AT I S N E E D E

    D ? yarn add document-register-element Pollyfil https://github.com/WebReflection/document-register-element import "document-register-element"
  10. C U S T O M E L E M

    E N T S + R E A C T import "document-register-element" import r from "ramda" import React from "react" import ReactDOM from "react-dom" function render(ComponentClass: ReactClass<any>) { return function() { function reducer(acc, node) { const merge = { [node.nodeName]: node.nodeValue, } return r.merge(merge, acc) } const props = r.reduce(reducer, {}, this.attributes) ReactDOM.render( <ComponentClass {...props}/>, this ) } } function detach() { ReactDOM.unmountComponentAtNode(this) } function registerCustomElement(ComponentClass: ReactClass<any>, tagName: string) { const elementPrototype = Object.create(HTMLElement.prototype) elementPrototype.attachedCallback = render(ComponentClass) elementPrototype.attributeChangedCallback = render(ComponentClass) elementPrototype.detachedCallback = detach elementPrototype.createdCallback = created try { return document.registerElement(tagName || ComponentClass.displayName, { prototype: elementPrototype, }) } catch(e) { rollbar.error(e) } } export default registerCustomElement
  11. R E G I S T E R A C

    U S T O M E L E M E N T function Widget(props) { ... } registerCustomElement(Widget, "x-widget")
  12. U S I N G I T node "x-widget" [

    attribute "count" "1" ] [] <x-widget count="1" /> Props for react
  13. I T W O R K S Elm in the

    middle React JS Routing, etc
  14. O U R C O N C E R N

    S • Preserve React state • CSS • Events from React to Elm • Redux • Relay
  15. R E A C T S TAT E React state

    (in custom element) is preserved fine Elm doesn't destroy React state
  16. E V E N T S F R O M

    R E A C T S O M E T H I N G H A P P E N E D G O T I T
  17. I S L I K E J Q U E

    RY / B A C K B O N E = = D O M E V E N T S
  18. E V E N T S F R O M

    R E A C T let customEventDecoder = Decode.at [ "detail" ] Decode.string decoder = Decode.map OnTriggerEvent customEventDecoder in node "x-widget" [ attribute "eventname" "trigger" , on "trigger" decoder ] [] Listen to DOM events
  19. const event = new CustomEvent(props.eventname, { detail: "Hello", bubbles: true,

    }) function send(e) { e.target.dispatchEvent(event) } return ( <section> <button onClick={send}>Send event</button> </section> ) E V E N T S F R O M R E A C T Trigger DOM events
  20. R E D U X O P E N T

    H E M E N U O K
  21. R E D U X const store = createStore(update) window.reduxStore

    = store E L M <Provider store={window.reduxStore}> <Widget {...props} /> </Provider> In custom element Outer layer
  22. PA S S I N G P R O P

    S To Elm via ports To Read via attrs Or Redux
  23. O T H E R E L M window is

    your friend w i n d o w . s h o w S u c c e s s = f u n c t i o n ( ) . . . w i n d o w . s h o w S u c c e s s ( . . . )
  24. N E A R F U T U R E

    Wrap all React widgets in custom element inside Elm