Получатель Vuex возвращает undefined

У меня есть приложение vue, использующее vex для хранения данных всего сайта, я получаю информацию о пользователе и помещаю ее в состояние перед созданием метода жизненного цикла следующим образом:

const app = new Vue({
    el: '#app',
    store,
    beforeCreate(){
        store.dispatch('currentUser');
    }
});

В моем пользовательском модуле у меня есть геттер, который получает имя пользователя, как показано ниже:

const getters = {
    getName(state){
        return state.user.name;
    }
};

В своих компонентах я пытаюсь получить доступ к получателю, чтобы отобразить имя пользователя в компоненте. Когда я смотрю на инструменты разработчика Vue Chrome, получатель не является неопределенным, но когда я консоль записываю результаты получателя, например, он говорит undefined.

mounted(){
    console.info(store.getters.getName);
},

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

Если в моем методе получения я делаю:

state.user

Я получаю это:

{ "id": 1, "name": "Test" }

Но когда я пытаюсь получить имя, я получаю неопределенное

Вот магазин:

import axios from "axios/index";

const state = {
    user: {},
};

const mutations = {
    FETCH_USER(state,user){
        state.user = user;
    },
    UPDATE_AVATAR(state,avatar){
        state.user.avatar = avatar;
    }
};

const getters = {
    getName(state){
      return state.user.name
    },
    avatar(state){
        return state.user.avatar;
    },
    userSocialNetworks(state){
        //return state.user.social_networks
    },
    schoolName(state){
        return state.user.school
    },
    schoolAbout(state){
        return state.user.school.about
    },
    schoolAddress(state){
        return state.user.school.address
    }
};

const actions = {
    currentUser: ({commit}) => {
        axios.get('/api/user').then(response => {
            commit('FETCH_USER', response.data);
        });

    }
}

export default {
    state,
    getters,
    actions,
    mutations

}


 {"user":{"user":{"name":"Test","email":"[email protected]","avatar":"http://www.gravatar.com/avatar/xxxx=300","city":null,"state":null,"zip":null,"address":null,"lat":null,"long":null,"role":"school","school":{"id":1,"about":null,"header":null,"name":"Test","user_id":1,"created_at":"2018-06-06 19:48:16","updated_at":"2018-06-06 19:48:16"},"following":[],"followers":[],"social_networks":[{"id":4,"user_id":1,"social_network_id":1,"network_url":"test.com/k","created_at":"2018-06-06 23:11:09","updated_at":"2018-06-06 23:15:19"},{"id":5,"user_id":1,"social_network_id":2,"network_url":"test.com/k","created_at":"2018-06-06 23:15:19","updated_at":"2018-06-06 23:15:19"},{"id":6,"user_id":1,"social_network_id":5,"network_url":"test.com/k","created_at":"2018-06-06 23:16:15","updated_at":"2018-06-06 23:16:15"}]}},"socialNetowrks":{"available_networks":[{"id":1,"network_name":"Facebook","created_at":null,"updated_at":null},{"id":2,"network_name":"Instagram","created_at":null,"updated_at":null},{"id":5,"network_name":"Twitter","created_at":null,"updated_at":null}]}}

вам нужно использовать this.$store.getters.getName в компонентах

Derek Pollard 07.06.2018 02:35

В чем разница

John Freedom 07.06.2018 02:46

Разница в том, что одно не определено, а другое - нет.

Derek Pollard 07.06.2018 02:47

@Derek Я получаю эту ошибку, используя хранилище таким образом. Ошибка в смонтированном хуке: «TypeError: не удается прочитать свойство 'name' of undefined»

John Freedom 07.06.2018 02:48

Это означает, что state.user не определен.

Derek Pollard 07.06.2018 02:59

@Derek, когда я просто выполняю state.user, он возвращает {"id": 1, "name": "Test"}, но name делает его неопределенным

John Freedom 07.06.2018 03:03

У вас Vue.use(vuex)?

Derek Pollard 07.06.2018 03:14

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

John Freedom 07.06.2018 03:36

Этот тип ошибки указывает на то, что vue.use(vuex); не выполняется. Что отображается на вкладке Vue DevTools Vuex?

Derek Pollard 07.06.2018 03:39

@Derek Отображает весь пользовательский объект с его именем и связями

John Freedom 07.06.2018 03:45

Покажи мне, как выглядит твой магазин, отредактируйте исходный пост

Derek Pollard 07.06.2018 03:47

@Derek Это в вопросе

John Freedom 07.06.2018 03:50

Я имел в виду код магазина, а не данные о состоянии магазина.

Derek Pollard 07.06.2018 03:53

@Derek - в вопросе пользовательский модуль

John Freedom 07.06.2018 03:58

Как вы экспортируете / импортируете свой магазин? это должно быть что-то вроде export default new Vuex.Store({}); и import store from './store'

Derek Pollard 07.06.2018 04:07

@Derek Я импортирую его, как и у вас, и все модули импортируются в файл index.js в каталоге магазина. В индексном файле я использую этот экспорт по умолчанию new Vuex.Store

John Freedom 07.06.2018 04:18

Попробуйте использовать mounted() вместо beforeCreate()

Derek Pollard 07.06.2018 04:23

@Derek Я перепробовал весь метод жизненного цикла, и та же ошибка сохраняется.

John Freedom 07.06.2018 04:33

У меня точно такая же проблема, вы когда-нибудь находили решение?

Miguel Stevens 05.11.2019 11:22
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
7
19
14 248
4

Ответы 4

Во-первых, в хуке beforeCreate методы еще не инициализированы. Самый простой способ обойти это - использовать вместо этого хук created:

const app = new Vue({
    el: '#app',
    store,
    created(){
        store.dispatch('currentUser'); // considering you have properly imported and exported vuex
    }
});

В вашем компоненте

import {mapGetters} from 'vuex';

export default {
  computed: {
    ...mapGetters(['getName'])
  }
}

Даже это не работает. Метод schoolName может возвращать объект, но не атрибут name.

John Freedom 07.06.2018 04:17

Вы можете попробовать это:

mounted() {
  setTimeout(() => {
    console.info(store.getters.getName);
  }, 400);
},

Попробуйте объявить конкретные переменные в магазине, чтобы правильно инициализировать данные:

const state = {
    user: {
        name: '',
        avatar: '',
        school: '',
        ...
    },
};

У меня была та же проблема, которую вы описали, пока я не сделал это.

Здесь вы столкнулись с двумя большими проблемами:

  1. Вы не должны обновлять объект непосредственно в магазине vuex, иначе вы потеряете реактивность

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

import assignDeep from 'assign-deep'; //Since you have nested structure you will need this

const state = {
    user: {
       name: '',
       school: {
          about: '',
          address: '',
       },
       // Make sure all properties are defined
    },

};

const mutations = {
    FETCH_USER(state,user){
        assignDeep(state.user, user);
    },
    UPDATE_AVATAR(state,avatar){
        state.user.avatar = avatar;
    }
};
  1. Вы пытаетесь получить доступ к свойству, которое асинхронно определено в состоянии и использует его синхронно (до того, как оно существует)

Сначала воспользуйтесь утилитой mapGetters vuex для упрощения использования.

import { mapGetters } from 'vuex';
//... In component definition
computed: {
  ...mapGetters({name: 'getName'})
}

Поскольку это вычисляемое свойство vue, ваш компонент будет повторно визуализироваться, когда он будет определен, и все должно отображаться правильно, вам просто нужно убедиться, что вы обрабатываете случай, когда он пуст, и, возможно, отображаете экран загрузки, пока он не будет

Например

<template>
  <div v-if = "!name" class = "loading"></div>
  <div v-else>{{name}}</div>
<template>

Вы также можете просто дождаться обновления собственности.

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

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

watch: {
  name: {
    handler(name, oldName) {
      if (name) {
        //Do something
      }
    },
    immediate: true
  }
}

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