elm/core

Conditional subscriptions don't work in 0.19.1

bigardone opened this issue · 4 comments

When having conditional subscriptions, like in a SPA with routes where different routes might have different subscriptions, they don't work anymore in 0.19.1.

SSCCE

module Main exposing (main)

import Browser exposing (Document)
import Browser.Navigation as Navigation
import Html exposing (Html, a, div, li, text, ul)
import Html.Attributes exposing (href)
import Time
import Url
import Url.Parser as Parser exposing (Parser, s)


-- MODEL

type alias Model =
    { navigation : Navigation
    , counter : Int
    }


type alias Navigation =
    { key : Navigation.Key
    , page : Page
    }


initialModel : Url.Url -> Navigation.Key -> Model
initialModel url key =
    { navigation =
        { key = key
        , page =
            case fromUrl url of
                Nothing ->
                    NotFound

                Just a ->
                    a
        }
    , counter = 0
    }


parser : Parser (Page -> b) b
parser =
    Parser.oneOf
        [ Parser.map Home Parser.top
        , Parser.map About (s "about")
        ]


fromUrl : Url.Url -> Maybe Page
fromUrl url =
    -- Treat fragment as path for convenience
    { url | path = Maybe.withDefault "" url.fragment, fragment = Nothing }
        |> Parser.parse parser


type Page
    = Home
    | About
    | NotFound


type alias Flags =
    ()


init : Flags -> Url.Url -> Navigation.Key -> ( Model, Cmd Msg )
init flags url key =
    ( initialModel url key, Cmd.none )



-- UPDATE


type Msg
    = UrlRequested Browser.UrlRequest
    | UrlChange Url.Url
    | Tick Time.Posix


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case Debug.log "" msg of
        UrlRequested urlRequest ->
            case urlRequest of
                Browser.Internal url ->
                    ( model, Navigation.pushUrl model.navigation.key (Url.toString url) )

                Browser.External href ->
                    ( model, Navigation.load href )

        UrlChange url ->
            let
                navigation =
                    model.navigation
            in
            ( { model
                | navigation =
                    { navigation
                        | page =
                            case fromUrl url of
                                Nothing ->
                                    NotFound

                                Just a ->
                                    a
                    }
              }
            , Cmd.none
            )

        Tick _ ->
            ( { model | counter = model.counter + 1 }, Cmd.none )



-- VIEW


view : Model -> Document Msg
view model =
    { title = "hello title"
    , body = [ bodyView model ]
    }


bodyView : Model -> Html Msg
bodyView model =
    div []
        [ text "hello world"
        , ul []
            [ li [] [ a [ href "#/" ] [ text "Home" ] ]
            , li [] [ a [ href "#/about" ] [ text "About" ] ]
            ]
        , div []
            [ case model.navigation.page of
                NotFound ->
                    text "Page not Found"

                Home ->
                    Html.div
                        []
                        [ text "Home page"
                        , Html.div
                            []
                            [ text <| String.fromInt model.counter ]
                        ]

                About ->
                    text "About page"
            ]
        ]



-- SUBSCRIPTIONS


subscriptions : Model -> Sub Msg
subscriptions model =
    case model.navigation.page of
        Home ->
            Time.every 1000 Tick

        _ ->
            Sub.none



-- MAIN


main : Program Flags Model Msg
main =
    Browser.application
        { init = init
        , update = update
        , view = view
        , subscriptions = subscriptions
        , onUrlRequest = UrlRequested
        , onUrlChange = UrlChange
        }

Expected

When visiting http://localhost:8000/src/Main.elm#/ for the first time, the counter should start increasing every second. Visiting the http://localhost:8000/src/Main.elm#/about should hide the counter. Going back to http://localhost:8000/src/Main.elm#/ should display de counter again and start increasing it again every second.

Actual

Visiting http://localhost:8000/src/Main.elm#/ starts the counter. Visiting http://localhost:8000/src/Main.elm#/about hides the counter. Going back to http://localhost:8000/src/Main.elm#/ shows the counter but it does not increase any more, unless you click on the home link twice.

  • Elm: 0.19.1
  • Browser: Chrome, Safari
  • Operating System: macOS, iOS

Possible issue

Some people have reported this problem and done some investigation about the possible root of the issue. Here you cand find what they have discovered https://elmlang.slack.com/archives/C13L7S5GR/p1572031426192200
This might also be related to elm/compiler#1776

The bug here is in how "synchronous commands" are handled internally. It should be fixed by this commit: 704dcc0

Trying out the commit locally with the changes, I am seeing the behavior you expect. So the fixed version should come out in a patch release (1.0.3) along with some other fixes. Thank you for the SSCCE, it really help test fixes that touch on really tricky code (task scheduling!)

Awesome! Thank you @evancz for putting effort into this :)

I believe issues like this one: elm/browser#62 also caused by the same flaw. If so, many related cases can be closed!
Thank you for the effort 👍

I've just tried out the elm/core 1.0.3 and everything related to conditional subscriptions is finally working fine 😍