30: Total Elm - JSToElm
All Episodes

30: Total Elm

Not treating ports as an http request is hard. We want to think if more as a messaging service using the actor model pattern, and set up a single pair of ports for our Elm and JS to interact. Let's see what that looks like, and if we understand it?

Better Ports

  • The actor model

    • concurrent and fault tolerant
    • info in / info out
    • like chatting in slack
    • Erlang / Elixir, web workers Screen Shot 2018-03-28 at 9.27.51 PM
  • Just One Port out going / One Port incoming

    • stop with the JS wrapping api
    • simplify JS down to its data
    • Treating JS as a black box
    • Incoming Data from JS to Elm and
    • Outgoing data for Elm to JS

      • Data will be a new type GenericData
      • {tag: String, data: Json.Encode.Value}
      • Tag will be our pattern match and tell us what to do with the data
  • How does that work in our case with React ?

    • initPorts can be function removed from living in the actual React component,
    • So in rendering another Elm ‘component’ would we want to have separate init methods ? Not really.
  • So don’t for get! “elm lang I cannot find module”

    • "source-directories": ["./src/elm"],
port module JSInterop exposing (..)

import Note exposing (Note, noteDecoder, noteListDecoder)
import Json.Decode exposing (Decoder, decodeValue)
import Json.Encode


sendData : OutgoingData -> Cmd msg
sendData info =
    case info of
        FetchNotes path ->
            outgoingData { tag = "FetchNotes", data = Json.Encode.string path }

        LogError err ->
            outgoingData { tag = "LogError", data = Json.Encode.string err }


receiveData : (IncomingData -> msg) -> (String -> msg) -> Sub msg
receiveData tagger onError =
    incomingData
        (\info ->
            case info.tag of
                "NotesLoaded" ->
                    tagger <| NotesLoaded <| decodeValue noteListDecoder info.data

                "IsAuthenticated" ->
                    tagger <| UpdateAuth True

                _ ->
                    onError <| "Unexpected info from outside: " ++ toString info
        )


type OutgoingData
    = FetchNotes String
    | LogError String


type IncomingData
    = NotesLoaded (Result String (List Note))
    | UpdateAuth Bool


type alias GenericData =
    { tag : String, data : Json.Encode.Value }


port outgoingData : GenericData -> Cmd msg


port incomingData : (GenericData -> msg) -> Sub msg

Picks

Resources

Follow

Published 29 Mar 2018

A show about learning Elm, Functional Programing, and generally leveling up as a JS developer.
JavaScript To Elm on Twitter