映射到嵌套组件的 Elm 效果

Elm Effects Mapped to Nested Component

本文关键字:Elm 效果 组件 嵌套 映射      更新时间:2023-09-26

在这个例子(RandomGifPair)中,对应于NewGif的更新实际上是如何在父组件触发RandomGif.update act model.left后执行的?似乎RandomGif.update NewGif maybeUrl需要在某处手动触发。更明确一点,RandomGifPair触发其左更新操作,并通过手动调用RandomGif的更新函数来返回模型/效果对。返回的效果通过Effects.map Left fx执行,然后继续到RandomGif中的getRandomGif函数。

getRandomGif : String -> Effects Action
getRandomGif topic =
  Http.get decodeUrl (randomUrl topic)
    |> Task.toMaybe
    |> Task.map NewGif
    |> Effects.task

据我了解,它将继续触发NewGif操作,由于Effects.map,现在也被标记为Left。我缺少图片的唯一部分是如何将此操作保持在 RandomGif 的范围内,以及与此更新的 NewGif 案例相对应的操作实际触发:

update : Action -> Model -> (Model, Effects Action)
update action model =
  case action of
    RequestMore ->
      (model, getRandomGif model.topic)
    NewGif maybeUrl ->
      ( Model model.topic (Maybe.withDefault model.gifUrl maybeUrl)
      , Effects.none
      )

当 Main.elm 只有来自 RandomGifPair 的更新功能时,因此没有 NewGif 的情况。

我敢肯定,答案在于我缺少的端口,Effects.map,forwardTo或任务的特定细节。

作为参考,这里尝试在javascript中解决问题,该脚本在NewGif的上层更新函数中包含条目,并在其中手动调用RandomGif.update。可能不是尝试了解榆树的最佳方式...

所有操作都进入您的顶级更新功能。无法将操作范围限定为子更新函数 - 它们始终位于顶部。因此,大多数程序会手动将操作路由到较低的更新功能。这就是这里正在发生的事情。所有操作都必须进入RandomGifPair.update,由该函数 a) 调用子函数和 b) 将结果存储在状态的正确位置。它可能令人惊讶地繁琐。

这是RandomGifPair.update中执行路由的特定点。

第 42 行说:"哦,这是一个Left动作?把里面的act给我。现在你有你想要的NewGifRequestMore存储在act,你知道它是绑定到左边的。第 44 行调用较低的更新函数,该函数知道如何处理它。第 46 行在模型中存储较低更新函数的结果(通过使用新的左重新创建整个模型并重用旧的右边)。

这一切都被围绕效果的样板所掩盖。如果你能先理解动作是如何流动的,然后回过头来将同样的逻辑应用于效果,我想这会变得更加清晰。

我可能在这里参加聚会有点晚了,但效果可以很容易地映射。

采取如下方法:

type alias ChildModel = { number : Int }
type alias Model = { firstChild : ChildModel }

type ChildMsg = One | Two | Three
type Msg Nothing | ChildMsg1 ChildMsg

childUpdate : ChildMsg -> ChildModel -> (ChildModel, Cmd ChildMsg)
childUpdate msg model =
  case msg of
    One -> { model | number = model.number + 1 }
    Two -> { model | number = model.number + 2 }
    Three -> { model | number = model.number + 3 }
update : Msg -> Model -> (Model, Msg)
update msg model =
  case msg of
    Nothing -> (model, Cmd.none)
    ChildMsg1 mesg -> -- heres where the update is mapped
      let
        (childModel, childMsg) = childUpdate mesg model.firstChild
      in
        ( { model | firstChild = childModel }, Cmd.map ChildMsg1 childMsg)

Cmd.map 将顶级消息映射到嵌套组件。想想蛇吃自己的尾巴。