60 votes

Comment définir l'état initial dans Vuex 2?

Je suis à l'aide de Vue.js 2.0 et Vuex 2.0 pour une petite application. Je suis de l'initialisation de la la banque dans le "créé" le cycle de vie d'un hameçon sur la racine de Vue de l'instance par l'appel d'une action qui récupère l'état initial à partir d'une API....comme dans mon Composant Racine:

const app = new Vue({
 el: "#app",
 router,
 store,
 data: {
     vacation: {},
 },
 components: {
    'vacation-status': VacationStatus,
 },
 created(){
    //initialize store data structure by submitting action.
    this.$store.dispatch('getVacation');
 },
 computed: {
 },
 methods: {
 }
});

Cela fonctionne très bien. Ici est l'action sur ma boutique que je vais appeler ici:

getVacation({commit}){
  api.getVacation().then(vacation => commit(UPDATE_VACATION, vacation))
}

La mutation que c'est commettre avec "UPDATE_VACATION' est ici:

[UPDATE_VACATION] (state, payload) {
  state.vacation = payload.vacation;
},

Mon Problème: Lorsque je charge l'application, tous mes composants, qui sont l'obtention de valeurs à partir de la boutique de générer des erreurs j'essaye d'accéder à 'undefined' valeurs sur le store. En d'autres termes, l'état n'a pas été initialisée encore.

Par exemple, j'ai un composant qui a getters dans les Composants Enfants comme ceci:

computed: {
        arrival () {
            return this.$store.getters.arrival
        },
        departure() {
            return this.$store.getters.departure
        },
        countdown: function() {
            return this.$store.getters.countdown
        }
} 

Tous ces accesseurs provoquer des erreurs parce que les "vacances" n'est pas défini sur l'état de l'objet. Il semble comme une asynchrones de problème pour moi, mais peut-être erroné. Suis-je l'initialisation de mon magasin de l'etat dans le mauvais endroit?

  Vue.use(Vuex);

  export default new Vuex.Store({
    state: {},
    getters: {
    getVacation: state => {
        return state.vacation
    },
    guests: state => {
        return state.vacation.guests
    },
    verifiedGuests: state => {
        return state.vacation.guests.filter(guest => guest.verified)
    },
    emergencyContacts: state => {
        return state.emergency_contacts
    },
    arrival: state => {
        return state.vacation.check_in
    },
    departure: state => {
        return state.vacation.check_out
    },
    countdown : state => {
        let check_in = new Date(state.vacation.check_in);
        let now = new Date();

        if ((now - check_in) > 0) {
            return 'This vacation started on ' + check_in;
        }

        let difference = check_in - now;
        let day = 1000 * 60 * 60 * 24;

        return Math.ceil(difference / day) + " days until your vacation";
    }
},
mutations: {
    [UPDATE_VACATION] (state, payload) {
        state.vacation = payload.vacation;
    },
    [ADD_GUEST] (state, payload) {
        state.vacation.guests.push(payload.guest);
    },
    [REMOVE_GUEST] (state, payload){
        state.vacation.guests.filter(guest => { debugger; return guest.id != payload.guest.id})
    },
    [UPDATE_GUEST] (state, payload){
        state.vacation.guests.map(guest => {
            // Refactor Object.assign to deep cloning of object
            return guest.id === payload.guest.id ? Object.assign({}, guest, payload.guest) : guest;
        })
    },
    [ADD_EMERGENCY] (state, payload){
        state.vacation.emergency_contacts.push(payload.emergency_contact)
    },
    [REMOVE_EMERGENCY] (state, payload){
        state.vacation.emergency_contacts.filter(contact => contact.id !== payload.emergency_contact.id)
    },
    [UPDATE_EMERGENCY] (state, payload){
        state.vacation.emergency_contacts.map(contact => {
            // Refactor not needed because emergency_contact is a shallow object.
           return contact.id === payload.emergency_contact.id ? Object.assign({}, contact, payload.emergency_contact) : contact;
        });
    }
},
actions: {
    getVacation({commit}){
      api.getVacation().then(vacation => commit(UPDATE_VACATION, vacation))
    },
    addGuest({commit}, guest){
        commit(ADD_GUEST, guest);
    },
    removeGuest({commit}, guest){
        commit(REMOVE_GUEST, guest);
    },
    updateGuest({commit}, guest){
        commit(UPDATE_GUEST, guest);
    },
    addEmergency({commit}, guest){
        commit(ADD_EMERGENCY, contact)
    },
    removeEmergency({commit}, contact){
        commit(REMOVE_EMERGENCY, contact)
    },
    updateEmergency({commit}, contact){
        commit(UPDATE_EMERGENCY, contact)
    },
    updateServer(store, payload){
      return api.saveVacation(payload)
    }
}

});

Seulement si la solution est claire pour tout le monde:

Je n'étais pas la définition de mon etat inital tout à fait correctement dans le magasin lui-même. Je tirais dans les données, et la mise à jour de la stocker correctement, mais le magasin a besoin d'être initialisé comme ceci:

export default new Vuex.Store({
 state: {
     vacation: {}//I added this, and then justed updated this object on create of the root Vue Instance
 },
});

43voto

AWolf Points 6214

Je pense que vous faites tout droit. Peut-être que vous êtes tout simplement pas de la création de la getters correctement (n'arrive pas à voir définition du code). Ou votre paramètre de l'état initial n'est pas correctement (pas non plus visible dans votre extrait de code).

Je voudrais utiliser mapState d'avoir les propriétés de l'état disponibles dans les composants.

Dans la démo simplement ajouter users le tableau en mapState paramètre de méthode et les données des utilisateurs seront disponibles sur le composant. (J'ai juste ajouté le getter users , pour montrer comment cela fonctionne. Ce n'est pas nécessaire si vous utilisez mapState.)

Jetez un oeil à la démo ci-dessous ou de ce violon.

const api =
  'https://jsonplaceholder.typicode.com/users'

const UPDATE_USERS = 'UPDATE_USERS'
const SET_LOADING = 'SET_LOADING'

const store = new Vuex.Store({
  state: {
    users: {},
    loading: false
  },
  mutations: {
    [UPDATE_USERS](state, users) {
      console.log('mutate users', users)
      state.users = users;
      console.log(state)
    }, [SET_LOADING](state, loading) {
      state.loading = loading;
    }
  },
  getters: {
    users(state) {
      return state.users
    }
  },
  actions: {
    getUsers({commit}) {
      commit(SET_LOADING, true);
      return fetchJsonp(api)
        .then((users) => users.json())
        .then((usersParsed) => {
          commit(UPDATE_USERS, usersParsed)
          commit(SET_LOADING, false)
        })
    }
  }
})

const mapState = Vuex.mapState;

const Users = {
  template: '<div><ul><li v-for="user in users">{{user.name}}</li></ul></div>',
  computed: mapState(['users'])
}

new Vue({
  el: '#app',
  store: store,
  computed: {
    ...mapState(['loading']),
      //...mapState(['users']),
      /*users () { // same as mapState
      	return this.$store.state.users;
      }*/
      users() { // also possible with mapGetters(['users'])
        return this.$store.getters.users
      }
  },
  created() {
    this.$store.dispatch('getUsers')
  },
  components: {
    Users
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/fetch-jsonp/1.0.5/fetch-jsonp.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/2.1.1/vuex.min.js"></script>
<div id="app">
  <div v-if="loading">loading...</div>
  <users></users>
  <pre v-if="!loading">{{users}}</pre>
</div>

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X