Как я могу использовать Cmd.map в функции обновления, используя несколько аргументов?

В Elm 0.19.1 у меня есть следующее сообщение (среди прочего):

      type Msg
    = Yay Multiselect.Msg

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        Yay sub ->
            let
                ( subModel, subCmd, _ ) =
                    Multiselect.update sub model
            in
            ( { model | multiselectC = subModel }, Cmd.map Yay subCmd )

Здесь я использую внешнюю библиотеку (Multiselect: https://github.com/inkuzmin/elm-multiselect). Для этого Msg я правильно следую примерам библиотеки. Целью здесь является обработка событий из этой библиотеки для обновления модели в этом модуле. Это правильно работает.

Вот в чем проблема. Я хочу добавить несколько аргументов в это сообщение. Например, добавимMultiselect.Modelк нему, создавая следующий тип:

      type Msg
    = Yay Multiselect.Msg Multiselect.Model

Это дает ошибку в (имеет смысл, поскольку отсутствует модель). Я попытался обновить -function в следующей функции:

      Yay sub msModel ->
            let
                ( subModel, subCmd, _ ) =
                    Multiselect.update sub msModel
            in
            ( { model | multiselectC = subModel }, Cmd.map (\cmd -> Yay cmd subModel) subCmd )

Это устранит ошибки компиляции и будет работать для большинства событий. Однако при некоторых некоторых событиях (например, при удалении элементов) библиотека будет вести себя неожиданно и отличаться от кода ранее.

Я также добавил ведение журнала, создав следующую командную строку:

Похоже, он правильно обновляет модель при удалении выбранного элемента. Однако при следующем инициированном событии похоже, что функция использует старую модель, удаляя обновление. В основном это означает, что ничего не происходит.

Как правильно написатьCmd.mapс несколькими аргументами, которые будут вести себя так же, как первая функция обновления только с 1 аргументом?

2 ответа

То, как вы передаете несколько аргументовMsgс правильно.

Но вы столкнулись с особым случаем, потому что вы передали состояние из представления.
В большинстве случаев лучше передавать только информацию о том, что должно измениться, а не как предполагаемое изменение, так и старое состояние как часть вашего сообщения.

Мое объяснение: такое поведение связано со средой выполнения Elm и оптимизацией рендеринга: DOM визуализируется только между 30 и 60 раз в секунду , а событие, которое запускается из представления, использует старое состояние. Таким образом, состояние вашей модели было обновлено (потому что оно выполняется максимально быстро), но позже перезаписано старым состоянием, которое все еще отображается в браузере.

Глядя на это изображение из официальной документации , можно заметить, что не каждое обновление вызывает немедленный повторный рендеринг DOM, а работа выполняется вне синхронизации:

Я действительно исправил эту проблему в моем случае. Оказывается, этот способ отображенияCmdправильно и работает. Однако в моем случае с использованием внешней библиотеки получается, что мое представление будет отправлять несколько сообщений в мою функцию обновления, используя один и тот же файл . Моя функция обновления обновляет эту модель, но эта обновленная модель не будет использоваться для сообщений, запускаемых из представления.

Чтобы исправить это, я удалил аргумент изMsg. Теперь я буду использовать другие аргументы (которые не будут обновляться между различными сообщениями) для поискаMultiselect.Modelв модели моего модуля. Это займет много кода, но это действительно работает.

Другие вопросы по тегам