代码之家  ›  专栏  ›  技术社区  ›  Mulan

elm中的序列http.get

  •  4
  • Mulan  · 技术社区  · 6 年前

    下面我有一个 button 尝试加载远程内容…

    import Post exposing (Post)
    import Html exposing (..)
    import Html.Events exposing (..)
    import Http
    import Json.Decode as Decode
    
    
    type alias Model =
        { posts : List Post }
    
    
    type Msg
        = Search String
        | PostsReceived (Result Http.Error (List Post))
    
    
    update : Msg -> Model -> ( Model, Cmd Msg )
    update msg model =
        case msg of
            Search s ->
                let
                    cmd =
                        (Decode.list Post.decode)
                            |> Http.get ("/posts?author=" ++ s)
                            |> Http.send PostsReceived
                in
                    ( model, cmd )
    
            PostsReceived (Ok posts) ->
                { model | posts = posts }
                    ! []
    
            PostsReceived (Err error) ->
                ( model, Cmd.none )
    
    
    view : Model -> Html Msg
    view model =
        button
            [ onClick (Search "amelia") ]
            [ text "Read posts by Amelia" ]
    

    这是一个有效的elm程序,只有一个小问题:api不允许我按字符串搜索。这是 允许

    /posts?author=amelia  => Malformed Request Error
    

    然而,这 允许

    /posts?author=2       => [ {...}, {...}, ... ]
    

    所以我必须 第一 找一个作家来找他/她 id ,和 然后 我可以使用作者的ID来获取帖子…

    /author?name=amelia => { id: 2, name: "amelia", ... }
    /posts?author=2
    

    我怎样才能把一个请求排在下一个之后呢?理想情况下,我希望将作者缓存在模型中的某个位置,因此我们只请求以前从未见过的作者。

    3 回复  |  直到 6 年前
        1
  •  5
  •   bdukes Jon Skeet    6 年前

    你可以用 Task.andThen 把两个任务连在一起。假设 /posts response包含author id,然后可以在处理响应时将该author id添加到模型中。

        Search s ->
            let
                getAuthor =
                    Author.decode
                        |> Http.get ("/author?name=" ++ s)
                        |> Http.toTask
                getPosts author =
                    (Decode.list Post.decode)
                        |> Http.get ("/posts?author=" ++ author.id)
                        |> Http.toTask
                cmd =
                    getAuthor
                        |> Task.andThen getPosts
                        |> Task.attempt PostsReceived
            in
                ( model, cmd )
    

    我把这个汇编在 https://ellie-app.com/DBJc6Kn3G6a1 如果有帮助的话

        2
  •  3
  •   Chad Gilbert    6 年前

    您可以使用 Task.andThen 是的。首先必须使用 Http.toTask 以下内容:

    postsByAuthorName : String -> Cmd Msg
    postsByAuthorName name =
        Http.get ("/author?name=" ++ name) (Decode.field "id" Decode.int)
            |> Http.toTask
            |> Task.andThen (\id ->
                Http.get ("/posts?author=" ++ toString id) (Decode.list decodePost)
                    |> Http.toTask)
            |> Task.attempt PostsReceived
    
        3
  •  2
  •   Jolanda    6 年前

    一个 a dictionary 还有一些味精的选择可以做到这一点。 您必须为author响应编写解码器,但除此之外,这应该可以工作

    type alias Model =
        { posts : List Post
        , authors : Dict String Int }
    
    
    type Msg
        = Search String
        | SearchAuthor String
        | AuthorReceived (Result Http.Error Int String)
        | PostsReceived (Result Http.Error (List Post))
    
    
    update : Msg -> Model -> ( Model, Cmd Msg )
    update msg model =
        case msg of
            Search author ->
                case (Dict.get author model.authors) of
                    Nothing ->
                        let 
                            cmd =
                                (Decode.list Post.decode)
                                    |> Http.get ("/author?name=" ++ author)
                                    |> Http.send AuthorReceived
                        in
                            (model,cmd)
    
                    Just num -> 
                        let
                            cmd =
                                (Decode.list Author.decode)
                                    |> Http.get ("/posts?author=" ++ num)
                                    |> Http.send PostsReceived
                        in
                            ( model, cmd )
    
            AuthorReceived (Ok number name) ->
                let
                    updatedAuthors = Dict.inster name number model.authors
                    cmd =
                        (Decode.list Post.decode)
                            |> Http.get ("/posts?author=" ++ number)
                            |> Http.send PostsReceived 
                in
                    {model | authors = updatedAuthors } ! [cmd]
    
            AuthorReceived (Err error) ->
                (mode, Cmd.none )
    
            PostsReceived (Ok posts) ->
                { model | posts = posts }
                    ! []
    
            PostsReceived (Err error) ->
                ( model, Cmd.none )
    
    
    view : Model -> Html Msg
    view model =
        button
            [ onClick (Search "amelia") ]
            [ text "Read posts by Amelia" ]