如何在 Vuex 2 中设置初始状态?

Posted

技术标签:

【中文标题】如何在 Vuex 2 中设置初始状态?【英文标题】:How do I set initial state in Vuex 2? 【发布时间】:2017-06-09 16:42:39 【问题描述】:

我正在为一个小型应用程序使用 Vue.js 2.0 和 Vuex 2.0。我正在通过调用从 API 检索初始状态的操作来在根 Vue 实例上的“已创建”生命周期挂钩中初始化存储......就像在我的 根组件 中一样:

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: 
 
);

这工作得很好。这是我在此处调用的商店中的操作:

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

使用“UPDATE_VACATION”提交的突变在这里:

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

我的问题:当我加载应用程序时,我所有从商店“获取”值的组件都会抛出错误,我正试图访问商店中的“未定义”值。换句话说,状态还没有被初始化。

例如,我有一个在 子组件 中有 getter 的组件,如下所示:

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

所有这些 getter 都会导致错误,因为在状态对象上未定义“假期”。这对我来说似乎是一个异步问题,但可能是错误的。 我是否在错误的位置初始化了我的商店状态?

  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)
    

);

只是为了让其他人清楚解决方案:

我没有在商店本身中正确设置我的初始状态。我正在提取数据并正确更新商店,但商店需要像这样初始化:

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

【问题讨论】:

【参考方案1】:

您可以创建一个返回初始状态的函数,并将其用于您的 Vuex 实例,如下所示:

function initialStateFromLocalStorage() 
    ...
    const empty = 
        status: '',
        token: '',
        user: null
    
    return empty;


export default new Vuex.Store(
    state: initialStateFromLocalStorage,
    ...

只要您返回一个状态对象,您就可以在该函数中做任何您想做的事情,对吧?

【讨论】:

在不能直接改变状态的严格模式下不起作用。【参考方案2】:

我认为你做的一切都是对的。也许您只是没有正确创建吸气剂(在您的代码中看不到任何定义)。或者您的初始状态设置不正确(在您的 sn-p 中也不可见)。

我会使用mapState 让组件中的状态属性可用。

在演示中,只需将users 添加到mapState 方法参数的数组中,用户数据将在组件中可用。 (我刚刚添加了 getter users 来展示它是如何工作的。如果您使用的是 mapState,则不需要这样做。)

请看下面的演示或fiddle。

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>

【讨论】:

感谢您的回复!我没有在根 Vue 实例中包含任何吸气剂,因为我在根的子组件中声明了所有吸气剂。那样可以么?或者我是否需要像您在小提琴中所做的那样,在与“创建”生命周期方法挂钩的同一实例中声明我的 getter? 我包括了我的整个商店,再次感谢您的帮助 不客气。在组件中添加 getter 是可以的。您可以在计算道具中添加吸气剂。你的组件。对于您的更新:我会将假期添加到您的状态对象中。喜欢这个state: vacation: 。我认为这是让反应性道具工作所必需的。 所以我最近改变了很多东西,但我回去仔细测试了你提到的state: vacation: ...修复了它。这真的很令人沮丧,但我很高兴我明白了。感谢您的帮助!

以上是关于如何在 Vuex 2 中设置初始状态?的主要内容,如果未能解决你的问题,请参考以下文章

如何在打字稿中设置初始 React 状态?

如何在redux中设置初始状态

使用 Vuex 4 在 Vue 3 中设置状态数据不起作用

如何在 Vuex 商店的 Vue.js 组件中设置动态样式

我应该在 vuex 状态下初始化哪种类型的数据以及何时初始化?

如何在布局/样式 XML 中设置状态栏色调颜色?