在 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.update
与 Decoder.update
- 合并
Main.Msg
与 Decoder.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 }
我正在研究 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.update
与Decoder.update
- 合并
Main.Msg
与Decoder.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 }