XState не остается в состоянии ожидания

Я использую xstate вместе с vuex в своем приложении:

  • vuex обрабатывает пользователя, вызовы API, элементы ответа и т. д.
  • xstate обрабатывает в основном сложные взаимодействия форм.

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

введите здесь описание изображения

введите здесь описание изображения

Я могу переключаться между состояниями, но в реальном приложении оно не может вернуться в исходное состояние (ожидание), а затем остаться в нем. Он всегда переходит обратно к следующему. Я не знаю, что я делаю неправильно, но я записал в консоль геттер formState, и вывод выглядит так:

formState idle 
formState createImageContent 

(он сразу переключается из состояния ожидания)

Вот базовый пример реализации: https://codesandbox.io/s/boring-shape-b4lgk


person sunwarri0r    schedule 24.05.2021    source источник
comment
Вы пробовали упростить пример? Когда я удалил часть Vuetify, у меня она работала без проблем.   -  person Kunukn    schedule 25.05.2021
comment
@Kunukn Спасибо за комментарий, я не пробовал без Vuetify, потому что реальное приложение (где возникает эта проблема) намного больше и зависит от Vuetify, но сейчас я посмотрю на него поближе...   -  person sunwarri0r    schedule 25.05.2021


Ответы (1)


Проблема в вашем компоненте Form.vue. В этой строке, если быть точным:

<v-window v-model="$store.getters['form/formState'].value">

Я не эксперт Vuetify, поэтому я не знаю, почему именно v-window обновляет v-model значением createImageContent, но это определенно так. Я обнаружил проблему, активировав Vuex строгий режим, который вызывает ошибку всякий раз, когда какое-либо состояние изменяется снаружи мутации. Он выдает ошибку, и из трассировки стека видно, что проблема вызвана v-window мутацией $store.getters['form/formState'].value

Простое исправление не использует v-model и вместо этого использует :value:

<v-window :value="$store.getters['form/formState'].value">

Демо

Обновить

Хорошо, я нашел причину. v-window имеет недокументированный реквизит mandatory (source), который по умолчанию равен true. В этом режиме v-window ожидает (и обеспечивает), что по крайней мере один из <v-window-item> дочерних компонентов всегда активен. Когда вы устанавливаете состояние idle, <v-window-item> с таким значением не существует, поэтому он сам выбирает один из элементов (сначала не отключен) и обновляет v-model. Поэтому другое решение — добавить :mandatory="false" к <v-window>.

Но не использовать v-model, вероятно, безопаснее и чище, поскольку геттер Vuex никогда не следует использовать с v-model.

person Michal Levý    schedule 27.05.2021