Как я могу использовать 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
в модели моего модуля. Это займет много кода, но это действительно работает.