如何将动作传递给Elm中的子组件

时间:2016-03-03 05:24:36

标签: 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的。

然后,也许我离开了,因为这是我榆树生活的第二天。

2 个答案:

答案 0 :(得分:3)

Elm Architecture Tutorial涵盖了子视图问题。再看看如何实现示例4。

简而言之,您需要在包含子操作的父级中使用Action:

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),这就是您遇到第二个错误的原因。

答案 1 :(得分:0)

编译器已经告诉你了答案。首先,

Address Action -> List ToDoItem.Model -> Html 这里的行动必须指定给儿童行动。只需像编译器告诉你的那样修复它:

view : Signal.Address TodoItem.Action -> Model -> Html

第二个,因为你buildToDos已经是一个列表,你只需要: div [] buildToDos

花一些时间理解类型注释并仔细遵循编译器,然后你应该能够自己解决这类问题。