在 Elm 中导入模块和 HTTP 请求

Importing modules and HTTP request in Elm

我正在研究 Elm,但我不确定如何正确解决这个问题。目的是每次通过 Save 方法创建项目时调用和外部 API。

编译器是这样说的:

The type annotation for `update` does not match its definition.

The type annotation is saying:
 
     Main.Msg -> Main.Model -> ( Main.Model, Cmd Main.Msg )
 
 But I am inferring that the definition has this type:
 
     Main.Msg -> Main.Model -> ( Main.Model, Cmd Decoder.Msg )at line 100 col 10

Main.elm

    bla bla bla

    import Components.Decoder as Decoder exposing (..)

    type alias Item =
        { name : String
        , qty : Int
        }


    type alias Model =
        { name : String
        , items : List Item
        , images : Images
        }


    type Msg
        = Save
        | Input String
        | Delete Item
        | Clear
        | Sum Item Int
        | NoOp

    bla bla bla


    update : Msg -> Model -> ( Model, Cmd Msg )
         update msg model =
          case msg of
              Save ->
              --( add model, Cmd.none )
              ( add model, fetchCmd )

              Input name ->
                ( { model | name = name }, Cmd.none )

               Sum item number ->
                 ( sum model item number, Cmd.none )

              Delete item ->
                ( delete model item, Cmd.none )

               Clear ->
                 ( { model | name = "" }, Cmd.none )

               NoOp ->
               ( model, Cmd.none )

Decoder.elm

module Components.Decoder exposing (..)

import Http exposing (..)
import Json.Decode as Decode exposing (Decoder, (:=))
import String
import Task exposing (Task)


type Msg
    = Fetch
    | FetchSucceed Images
    | FetchFail Http.Error


type alias Model =
    { id : Int
    , albumId : Int
    , title : String
    , url : String
    , thumbnailUrl : String
    }


type alias Images =
    List Model


url : String
url =
    "https://jsonplaceholder.typicode.com/photos"


stringToInt : Decoder String -> Decoder Int
stringToInt d =
    Decode.customDecoder d String.toInt


decoder : Decoder Model
decoder =
    Decode.object5 Model
        ("id" := Decode.string |> stringToInt)
        ("albumId" := Decode.string |> stringToInt)
        ("title" := Decode.string)
        ("url" := Decode.string)
        ("thumbnailUrl" := Decode.string)


decoderAll : Decoder Images
decoderAll =
    Decode.list decoder


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        Fetch ->
            ( model, fetchCmd )

        FetchSucceed images ->
            ( model, Cmd.none )

        FetchFail _ ->
            ( model, Cmd.none )


fetchTask : Task Http.Error Images
fetchTask =
    Http.get decoderAll url


fetchCmd : Cmd Msg
fetchCmd =
    Task.perform FetchFail FetchSucceed fetchTask


subscriptions : Model -> Sub Msg
subscriptions model =
    Sub.none

我不建议过早地将您的应用程序拆分成单独的组件。

您面临的问题主要是由于 Decoder.fetchCmd 导致 Decoder.Msg,而您在 Main.update

中使用它

简单

如果您不打算在其他任何地方重复使用 Decoder,我建议将逻辑放回 Main.elm:

  • 合并 Main.updateDecoder.update
  • 合并 Main.MsgDecoder.Msg
  • Decoder.Model 必须是 Main.Model
  • 的一部分
  • 在单个 update 函数中处理所有事情

可重复使用

无论您想从服务器检索什么数据,如果您打算将其中的一些数据输出给用户,它都应该存储在应用程序的状态中。

如果你真的想要一个可重用的组件来发送 Http.get,你将不得不做这样的事情:

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        Save ->
            -- Map Decoder.msg to Main.DecoderMsg
            ( add model, Cmd.map DecoderMsg fetchCmd )

        DecoderMsg msg ->
            let
                -- Pass the message and handle the update.
                ( fetchedAlbumList, decoderCmd ) =
                    Decoder.update msg model.albumList
            in
                -- Put retrieved data in the application state
                { model | albumList = fetchedAlbumList }