如何将动作传递给 Elm 中的子组件
How to pass an action to a child component in Elm
我试用 Elm 才几天,遇到了一些我无法弄清楚的看似常见的情况。
我有一个包含项目列表的父组件。为了呈现列表,我有一个子组件,以便父组件调用传递地址和模型的子组件的视图函数。由于 Action 类型不同,我认为编译器对此有所抱怨,但我真的不确定。
父组件:
type alias Model = List ToDoItem.Model
type Action
= Remove Int
update : Action -> Model -> Model
update action model =
case action of
Remove id ->
List.filter (\todo -> todo.id /= id) model
view : Signal.Address Action -> Model -> Html
view address model =
let
buildToDos =
List.map (ToDoItem.view address) model
in
div [] [ buildToDos ]
子组件:
type alias Model =
{ id : Int
, name : String
, description : String
, complete: Bool
}
type alias ID = Int
type Action
= Toggle Bool
update : Action -> Model -> Model
update action model =
case action of
Toggle toggle ->
if toggle == True then
{ model | complete = False }
else
{ model | complete = True }
view : Signal.Address Action -> Model -> Html
view address model =
let
toggleText : Bool -> String
toggleText complete =
case complete of
True -> "Incomplete"
False -> "Complete"
in
div
[ class "wrapper" ]
[ span [] [ text ("[" ++ toString model.id ++ "]") ]
, span [ class "name" ] [ text model.name ]
, div [ class "description" ] [ text model.description ]
, a [ onClick address (Toggle model.complete)] [ text (toggleText model.complete)]
]
编译器错误:
-- TYPE MISMATCH ----------------------------------------------
The type annotation for `view` does not match its definition.
20│ view : Signal.Address Action -> Model -> Html
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The type annotation is saying:
Address Action -> List ToDoItem.Model -> Html
But I am inferring that the definition has this type:
Address ToDoItem.Action -> List ToDoItem.Model -> Html
-- TYPE MISMATCH ----------------------------------------------
The 2nd argument to function `div` is causing a mismatch.
26│ div [] [ buildToDos ]
^^^^^^^^^^^^^^
Function `div` is expecting the 2nd argument to be:
List VirtualDom.Node
But it is:
List (List Html)
如何正确声明子组件的视图函数或从父组件正确传递参数给子视图函数?
实际上,我实际上并不想将任何操作传递给子组件 - 我只是想呈现它。子组件中的操作是针对那里的 onClick 的。
话又说回来,也许我离题太远了,因为这是我在 Elm 生活的第 2 天。
Elm Architecture Tutorial 涵盖子视图问题。再看看例子4是如何实现的
简而言之,您需要在包装子动作的父级中有一个动作:
type Action = Remove Int | ToDo Int ToDoItem.Action
并且您需要将此操作转发到 update
中的相应项目。
在 view
中,您需要为每个 ToDoItem 视图创建一个转发地址。
view : Signal.Address Action -> Model -> Html
view address model =
let
fwd idx = Signal.forwardTo address (ToDo idx)
toDoList =
List.indexedMap (\(idx, m) -> ToDoItem.view (fwd idx) m) model
in
div [] toDoList
请注意,您的旧 buildToDos
已经是一个列表,并且说 [buildToDos]
实际上是在说 List (List Html)
,这就是您出现第二个错误的原因。
编译器已经告诉你答案了。首先,
Address Action -> List ToDoItem.Model -> Html
此处的 Action 必须指定给子 Action。就像编译器告诉你的那样修复它:
view : Signal.Address TodoItem.Action -> Model -> Html
第二个,因为你的buildToDos
已经是列表了,你只需要:
div [] buildToDos
花一些时间了解类型注释并仔细遵循编译器,那么您应该能够自己解决此类问题。
我试用 Elm 才几天,遇到了一些我无法弄清楚的看似常见的情况。
我有一个包含项目列表的父组件。为了呈现列表,我有一个子组件,以便父组件调用传递地址和模型的子组件的视图函数。由于 Action 类型不同,我认为编译器对此有所抱怨,但我真的不确定。
父组件:
type alias Model = List ToDoItem.Model
type Action
= Remove Int
update : Action -> Model -> Model
update action model =
case action of
Remove id ->
List.filter (\todo -> todo.id /= id) model
view : Signal.Address Action -> Model -> Html
view address model =
let
buildToDos =
List.map (ToDoItem.view address) model
in
div [] [ buildToDos ]
子组件:
type alias Model =
{ id : Int
, name : String
, description : String
, complete: Bool
}
type alias ID = Int
type Action
= Toggle Bool
update : Action -> Model -> Model
update action model =
case action of
Toggle toggle ->
if toggle == True then
{ model | complete = False }
else
{ model | complete = True }
view : Signal.Address Action -> Model -> Html
view address model =
let
toggleText : Bool -> String
toggleText complete =
case complete of
True -> "Incomplete"
False -> "Complete"
in
div
[ class "wrapper" ]
[ span [] [ text ("[" ++ toString model.id ++ "]") ]
, span [ class "name" ] [ text model.name ]
, div [ class "description" ] [ text model.description ]
, a [ onClick address (Toggle model.complete)] [ text (toggleText model.complete)]
]
编译器错误:
-- TYPE MISMATCH ----------------------------------------------
The type annotation for `view` does not match its definition.
20│ view : Signal.Address Action -> Model -> Html
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The type annotation is saying:
Address Action -> List ToDoItem.Model -> Html
But I am inferring that the definition has this type:
Address ToDoItem.Action -> List ToDoItem.Model -> Html
-- TYPE MISMATCH ----------------------------------------------
The 2nd argument to function `div` is causing a mismatch.
26│ div [] [ buildToDos ]
^^^^^^^^^^^^^^
Function `div` is expecting the 2nd argument to be:
List VirtualDom.Node
But it is:
List (List Html)
如何正确声明子组件的视图函数或从父组件正确传递参数给子视图函数?
实际上,我实际上并不想将任何操作传递给子组件 - 我只是想呈现它。子组件中的操作是针对那里的 onClick 的。
话又说回来,也许我离题太远了,因为这是我在 Elm 生活的第 2 天。
Elm Architecture Tutorial 涵盖子视图问题。再看看例子4是如何实现的
简而言之,您需要在包装子动作的父级中有一个动作:
type Action = Remove Int | ToDo Int ToDoItem.Action
并且您需要将此操作转发到 update
中的相应项目。
在 view
中,您需要为每个 ToDoItem 视图创建一个转发地址。
view : Signal.Address Action -> Model -> Html
view address model =
let
fwd idx = Signal.forwardTo address (ToDo idx)
toDoList =
List.indexedMap (\(idx, m) -> ToDoItem.view (fwd idx) m) model
in
div [] toDoList
请注意,您的旧 buildToDos
已经是一个列表,并且说 [buildToDos]
实际上是在说 List (List Html)
,这就是您出现第二个错误的原因。
编译器已经告诉你答案了。首先,
Address Action -> List ToDoItem.Model -> Html
此处的 Action 必须指定给子 Action。就像编译器告诉你的那样修复它:
view : Signal.Address TodoItem.Action -> Model -> Html
第二个,因为你的buildToDos
已经是列表了,你只需要:
div [] buildToDos
花一些时间了解类型注释并仔细遵循编译器,那么您应该能够自己解决此类问题。