How to set initial values for data from vuex?
You were right, computeds are evaluated after the initial data
function is called.
Quick fix
In the comments, @Jacob Goh mentioned the following:
$store
should be ready before data function is called. Therefore,firstName: this.$store.state.userProfile.firstName
should just work.
export default { name: 'EditAccount', data() { return { accountInfo: { firstName: this.$store.state.userProfile.firstName } } }};
Really need computeds?
See @bottomsnap's answer, where setting the initial value can be done in the mounted
lifecycle hook.
With your code, it would look like this:
import { mapState } from 'vuex';export default { name: 'EditAccount', computed: { ...mapState(['userProfile']) }, data() { return { accountInfo: { firstName: '' } } } mounted() { this.accountInfo.firstName = this.userProfile.firstName; }};
Though it may render once without the value, and re-render after being mounted.
Container versus presentation
I explain Vue's communication channels in another answer, but here's a simple example of what you could do.
Treat the Form component as presentation logic, so it doesn't need to know about the store, instead receiving the profile data as a prop.
export default { props: { profile: { type: Object, }, }, data() { return { accountInfo: { firstName: this.profile.firstName } }; }}
Then, let the parent handle the business logic, so fetching the information from the store, triggering the actions, etc.
<template> <EditAccount :profile="userProfile" :submit="saveUserProfile"/></template><script>import { mapState, mapActions } from "vuex";export default { components: { EditAccount }, computed: mapState(['userProfile']), methods: mapActions(['saveUserProfile'])}</script>
While Jacob is not wrong saying that the store is ready, and that this.$store.state.userProfile.firstName
will work, I feel this is more a patch around a design problem that can easily be solved with the solution above.
Bind your input with v-model as you were:
<div id="app"> <input type="text" v-model="firstName"></div>
Use the mounted lifecycle hook to set the initial value:
import Vue from 'vue';import { mapGetters } from 'vuex';new Vue({ el: "#app", data: { firstName: null }, computed: { ...mapGetters(["getFirstName"]) }, mounted() { this.firstName = this.getFirstName } })