【问题标题】:Sequence Http.get in ElmElm 中的序列 Http.get
【发布时间】:2018-06-29 00:52:12
【问题描述】:

下面我有一个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

如何在下一个请求之后对一个请求进行排序?理想情况下,我想将作者缓存在模型中的某个位置,这样我们只请求我们以前从未见过的作者。

【问题讨论】:

    标签: elm elm-architecture


    【解决方案1】:

    您可以使用Task.andThen 将两个任务链接在一起。假设 /posts 响应包含作者 ID,然后您可以在处理响应时将该作者 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 进行了编译

    【讨论】:

    • 这是我想象中的解决方案,但不知道如何用 Elm 表达。您是否看到将作者复制到 model.authors 这样的缓存的简单方法,这样我们就可以避免多次获取同一作者? Task.map2 之类的东西,但不太适合...
    • 我认为收到的帖子会同时包含作者 ID 和姓名,因此您可以在 update 函数的 PostsReceived 部分处理它。
    • 如果没有,您可以将作者 ID 添加到从 getPosts 返回的值中,例如 (Decode.list Post.decode) |> Decode.map (\posts -> { id = author.id, name = author.name, posts = posts })
    【解决方案2】:

    您可以使用Task.andThen 将任务链接在一起。您首先必须使用 Http.toTask 将 Web 请求转换为任务:

    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】:

      a dictionary 和更多的 Msg 选项应该可以做到这一点。 您必须为作者响应编写解码器,但除此之外应该可以工作

      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" ]
      

      【讨论】:

        猜你喜欢
        • 2016-03-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-02
        • 1970-01-01
        • 2020-06-05
        • 1970-01-01
        相关资源
        最近更新 更多