Проблема реактивности с mapGetters только при первой загрузке - PullRequest
4 голосов
/ 11 июля 2019

Я использую помощник mapGetters из VueX, но у меня есть некоторые проблемы только при первой загрузке страницы, это не реагирует ... Позвольте мне показать вам:

мой HTML-шаблон, вызывающий изменение:

<input type="number" value="this.inputValue" @change="this.$store.dispatch('setInputValue', $event.target.value)">

мой магазин получает значение

{
    state: {
        appValues: {
            inputValue: null
        },
    },
    getters: {
        getInputValue: (state) => {
            return state.appValues.inputValue;
        },
    },
    mutations: {
        setInputValue(state, value) {
            state.appValues.inputValue = value;
        },
    },
    actions: {
        setInputValue(context, payload) {
            return new Promise((resolve, reject) => {
                context.commit('setInputValue', payload);
                resolve();
            });
        },
    }
}

а потом мой компонент слушает магазин:

import {mapGetters} from 'vuex';

computed: {
    ...mapGetters({
        inputValue: 'getInputValue',
    }),
}
watch: {
    inputValue: {
        deep: true,
        immediate: true,
        handler(nVal, oVal) {
            console.log("inputValue", nVal, oVal);
        }
    },
}

Итак, теперь, когда я впервые загружаю страницу, я получаю этот console.log "inputValue" null undefined, что совершенно нормально, потому что, поскольку у меня ничего нет в моем магазине, оно дает мне значение по умолчанию null .

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

Затем я перезагружаю страницу и при загрузке я получаю этот console.log "inputValue" 5 undefined (5 - это значение, которое я ввел ранее), так что, как вы можете видеть, когда я ранее менял ввод, он хорошо сохранял значение в магазине, но вычисленное значение не обновлялось само по себе ...

Теперь, когда я изменяю значение ввода, у меня есть журнал консоли, например, "inputValue" 7 5, поэтому он работает так, как я хотел бы, чтобы он работал с самого начала ...

Что я делаю не так? Почему при первой загрузке вычисленное значение не является реактивным?

Спасибо за ваши ответы ...

Ответы [ 4 ]

1 голос
/ 11 июля 2019

Я думаю, что лучший способ решить эту проблему - сохранить локальную переменную с помощью наблюдателя, а затем обновить vuex при изменении локальной:

На вашем компоненте:

<input type="number" v-model="value">

data() {
    return {
        value: ''
    };
},

computed: {
    ...mapGetters({
        inputValue: 'getInputValue'
    })
}

watch: {
    value(value){
        this.$store.dispatch('setInputValue', value);
    },

    inputValue(value) {
        console.log('inputValue', value);
    }
},

created() {
    // set the initial value to be the same as the one in vuex
    this.value = this.inputValue;
}
0 голосов
/ 12 июля 2019

Хорошо, так ... Я нашел проблему, и она не была связана с моими примерами, я не могу объяснить, почему, но я попытаюсь объяснить, как:

В моем магазине у меня есть следующий метод:

mutations: {
    deleteAppValues(state) {
        state.appValues = null;
    }
}

Я использовал это при выходе из системы, или когда пользователь впервые зашел на страницу и не вошел в систему ... Так что же происходит?

  1. Пользователь сначала загружает страницу, хранилище хорошо инициализируется, а индекс inputValue инициализируется нулевым значением, поэтому он существует ...
  2. ... Но поскольку пользователь не зарегистрирован, я уничтожаю хранилище, поэтому теперь inputValue не равно нулю, его просто не существует ...
  3. Попытка использовать mapGetters для чего-то, что не существует, реактивность не будет работать, поэтому, если я отправлю изменение, ключ хранилища будет создан, но так как mapGetters был инициализирован с несуществующим ключом, он не слушает реактивность ...
  4. После перезагрузки страницы ключ теперь существует в хранилище, поэтому к нему можно подключить геттер, и теперь все работает нормально ...

Это в точности объяснение того, что пошло не так с моим кодом ... Поэтому, чтобы он работал нормально, я просто изменил свою мутацию уничтожения на:

mutations: {
    deleteAppValues(state) {
        state.appValues = {
            inputValue: null,
        };
    }
}

Таким образом, ключ inputValue объекта store всегда будет существовать, и поэтому получатель не потеряет свою реактивность ...

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

0 голосов
/ 11 июля 2019

В шаблоне есть несколько небольших ошибок. Должно быть так:

<input type="number" :value="inputValue" @change="$store.dispatch('setInputValue', $event.target.value)">

Я удалил this. в нескольких местах и ​​поставил : перед value. После внесения этих изменений все работает, как и ожидалось. this.$store вызывал консольные ошибки для меня при использовании Vue 2.6.10.

Я бы добавил, что вы используете событие change. Это стандартное событие DOM change, и оно не будет срабатывать, пока поле не размывается. Так что, если вы просто начнете печатать, вы не увидите, чтобы что-то происходило в консоли. Было бы лучше использовать input, если вы хотите, чтобы он обновлялся при каждом нажатии клавиши. В качестве альтернативы вы можете использовать v-model с геттером и сеттером (см. https://vuex.vuejs.org/guide/forms.html#two-way-computed-property).

Я подозреваю, что когда вы перезагружали страницу, которая вызывала событие изменения, потому что оно размыло поле.

0 голосов
/ 11 июля 2019

Пожалуйста, посмотрите на этот образец: https://codesandbox.io/s/vuex-store-ne3ol

Ваша ошибка в том, что вы используете this ключевое слово в шаблоне. Не следует использовать this в шаблоне кода.

<input
      type="number"
      value="inputValue"
      @change="$store.dispatch('setInputValue', $event.target.value)"
    >

Бонусный совет: избыточно использовать геттер для возврата состояния по умолчанию если вы можете просто использовать mapState, чтобы вернуть состояние.

...