最近在重构博客系统前端代码,企图更换框架为Nuxtjs

踩了不少坑,有webpack打包的坑,有服务端渲染的坑

今天记录一下久攻不下的store 状态树相关问题

实践

博客系统有全局布局组件,如:Header(页首),Footer(页脚),Player(播放器),ChatRoom(聊天室)等等状态组件

由于Nuxt.js是服务端渲染框架,在碰到下面这种需要动态请求数据控制的组件不太友好:

<template>
   <Player v-if="isPlayer" />
</template>
javascript

起初尝试使用asyncData实现服务端数据请求:

//layout/default.vue
<template>
   <Player v-if="isPlayer" />
</template>

<script>
   export default {
      name:"default",
      async asyncData({store}) {
          let data = await axios.get("https://******/***")
          return {
              isPlayer: data.data
         }
    }
}
javascript

但是报错Cannot read property 'isPlayer' of undefined

后了解是因为根据Nuxt.js的设计,非页面组件是无法使用asyncData来实现服务端请求数据的

于是如果使用asyncData来实现服务端渲染,会出现asyncData钩子函数不被调用,因而报错

因此此方式失败,后尝试使用middleware(中间层)来更新store,在再页面中调用store.state来实现

//layout/default.vue
<template>
   <Player v-if="$store.state.isPlayer" />
</template>

<script>
   export default {
      name:"default",
      middleware({store}){
         axios.get("https://******/***")
         .then(({data})=>{
            console.log("middleware",data.data)
            store.commit("checkIsPlayer", data.data);
            console.log("middleware store",store.state.isPlayer)
         })
      }
  }
</script>
javascript

其中store/index.js源代码

// store/index.js
import Vue from "vue";
import Vuex from "vuex";
import axios from "axios";
Vue.use(Vuex);

export default ()=>new Vuex.Store({
  state: {
     isPlayer: {}
  },
  mutations: {
     checkIsPlayer(state, isPlayer) {
       state.isPlayer= isPlayer;
     }
   }
})
javascript

但是还是失败,考虑是异步请求执行顺序的问题,虽然state值成功设置,但是页面渲染仍获取为null值,即跟不上页面渲染

于是考虑更高级别优先级的生命周期函数——nuxtServerInit钩子函数
改写store/index.js,添加nuxtServerInit

// store/index.js
import Vue from "vue";
import Vuex from "vuex";
import axios from "axios";
Vue.use(Vuex);

export default ()=>new Vuex.Store({
  state: {
    isPlayer: {}
  },
  mutations: {
    checkIsPlayer(state, isPlayer) {
      state.isPlayer= isPlayer;
    }
  },
  actions: {
     nuxtServerInit(store){
       axios.get("https://******/***")
       .then(({data})=>{
          console.log('nuxtServerInit',data)
          store.commit('isPlayer', data.data)
          console.log(store.state)
       })
     }
   }
})
javascript

相应地,layout/default.vue更改为:

//layout/default.vue
<template>
   <Player v-if="$store.state.isPlayer" />
</template>
javascript

但是依旧失败,虽然state值成功设置,但是页面渲染仍获取为null值,即还是跟不上页面渲染
经过实践

后经过多次尝试,将nuxtServerInit改为异步请求成功解决问题:

// store/index.js
import Vue from "vue";
import Vuex from "vuex";
import axios from "axios";
Vue.use(Vuex);

export default ()=>new Vuex.Store({
  state: {
    isPlayer: {}
  },
  mutations: {
    checkIsPlayer(state, isPlayer) {
      state.isPlayer= isPlayer;
    }
  },
  actions: {
     async nuxtServerInit(store){
       await axios.get("https://******/***")
       .then(({data})=>{
          console.log('nuxtServerInit',data)
          store.commit('isPlayer', data.data)
          console.log(store.state)
       })
     }
   }
})
javascript

页面成功渲染且不报错
完工。

打赏
  • 微信
  • 支付宝
评论
来发评论吧~
···

歌手: