Vuex 父组件调用action 子组件getter 为空

问题描述

组件关系图
图片描述

Detail.vuue -> Content.vue -> DetailLeft.vue

Detail.vue 调用action

DetailLeft.vue 调用getter

问题出现的环境背景及自己尝试过哪些方法

希望用vuex解决 因为Detail Content DetailLeft 有3层组件

相关代码

// 请把代码文本粘贴到下方(请勿用图片代替代码)

<template>
  <div class="page-content">
      <detail-content></detail-content>
  </div>
</template>

<script>
import { mapActions } from 'vuex'
import DetailContent from 'pages/detail/components/Content'
export default {
  name: 'detail',
  props: {
    id: {
      required: true
    }
  },
  components: {
    DetailContent
  },
  created () {
    this._getBlogArticleById()
  },
  watch: {
    // 如果路由有变化,会再次执行该方法
    '$route': '_getBlogArticleById'
  },
  methods: {
    _getBlogArticleById () {
      this.singleNew(this.id)
    },
    ...mapActions([
      'singleNew'
    ])
  }
}
</script>

<style lang="stylus" scoped>

</style>

DetailLeft.vue

<template>
  <div class="c_left">
    <div class="post">
      <div class="post-title">
        <div class="breadcrumbs">
          <span>
            <router-link :to="'/'">
              <span>首页</span>
            </router-link>
            <span class="sep">></span>
            <span class="current">
              <router-link :to="'/'">{{singleNew.blogCategoryVo.categoryName}}</router-link>
            </span>
            <span class="sep">></span>
            <span class="current">
              正文
            </span>
          </span>
        </div>
        <h1 class="title">{{singleNew.title}}</h1>
        <div class="post_icon">
          <span class="postauthor">
            <img
                alt
                src="https://secure.gravatar.com/avatar/afa39accf8700cbbe7b13e1d01aa5b17?s=96&amp;d=mm&amp;r=g"
                data-original="https://secure.gravatar.com/avatar/afa39accf8700cbbe7b13e1d01aa5b17?s=96&amp;d=mm&amp;r=g"
                srcset="https://secure.gravatar.com/avatar/afa39accf8700cbbe7b13e1d01aa5b17?s=192&amp;d=mm&amp;r=g 2x"
                class="avatar avatar-96 photo"
                height="96"
                width="96"
              >
            <a href="#" target="_blank">{{singleNew.author}}</a>
          </span>
          <span class="postcat">
            <svg class="icon" aria-hidden="true">
              <use xlink:href="#icon-category"></use>
            </svg>
            <a href="#">{{singleNew.blogCategoryVo.categoryName}}</a>
          </span>
          <span class="postclock">
            <svg class="icon" aria-hidden="true">
              <use xlink:href="#icon-time"></use>
            </svg>
            {{singleNew.postTime}}
          </span>
          <span class="posteye">
            <svg class="icon" aria-hidden="true">
              <use xlink:href="#icon-eye"></use>
            </svg>
            {{singleNew.browseCount}}
          </span>
          <span class="postcomment">
            {{singleNew.commentCount}}
          </span>
          <span class="postlike">
            <svg class="icon" aria-hidden="true">
              <use xlink:href="#icon-like"></use>
            </svg>
            {{singleNew.pollCount}}
          </span>
        </div>
      </div>
      <div class="post-content" v-html="singleNew.content">
      </div>
      <div class="clearfix"></div>
      <div class="post-options">
        <a href="#" title="like" class="btn-likes like current">
          <span class="s-like">
            <svg class="icon" aria-hidden="true">
              <use xlink:href="#icon-like"></use>
            </svg>
            like
          </span>
          <span class="count num">({{singleNew.commentCount}})</span>
        </a>
      </div>
    </div>
    <message></message>
  </div>
</template>

<script>
import { mapGetters } from 'vuex'
import Message from 'components/message/Message'
export default {
  name: 'detailLeft',
  components: {
    Message
  },
  computed: {
    ...mapGetters([
      'singleNew'
    ])
  }
}
</script>

<style lang="stylus" scoped>
  .post
    .post-title
      .breadcrumbs
        margin-bottom: 25px
        span
          color: #748594
          font-size: 12px
        span.sep
          margin: 0 5px
        span.current
          color: #a5aeb5
      .post_icon
        color: #748594
        font-size: 12px
        display: block
        span
          margin-right: 10px
          display: inline-block
          position: relative
        .postauthor
          img
            display: inline-block
            width: 30px
            height: 30px
            border-radius: 50%
            -moz-border-radius: 50%
            -webkit-border-radius: 50%
            border: 1px solid rgba(216, 216, 216, 0.81)
            margin-right: 10px
    .post-options
      .btn-likes
        width: 130px
        height: 40px
        line-height: 40px
        border: 1px solid #F74840
        box-shadow: none
        background: #fff
        display: inline-block
        text-align: center
        margin: 0 2px
        color: #F74840
        font-size: 14px
        text-decoration: none
        border-radius: 0
        -webkit-transition: all .3s ease
        -o-transition: all .3s ease
        transition: all .3s ease
        border-radius: 2px
        -moz-border-radius: 2px
        -webkit-border-radius: 2px
      .btn-likes.current
        background-color: #F74840
        color: #fff
        border-color: #F74840
</style>

Vuex 相关
state.js

const state = {
  news: [],
  singleNew: null
}

export default state

action.js

import * as types from './mutation-types'
import { ERR_OK } from 'common/js/config'
import { getBlogArticleById } from 'api/blog/article'

export const news = function ({commit}, {records}) {
  commit(types.SET_NEWS, records)
}

export const singleNew = function ({commit}, id) {
  getBlogArticleById(id).then((res) => {
    if (res.code === ERR_OK) {
      // 将列表数据放入 vuex actions中
      commit(types.SET_SINGLE_NEW, res.data)
    }
  })
}

mutations.js

import * as types from './mutation-types'

const mutations = {
  [types.SET_NEWS] (state, news) {
    state.news = news
    try {
      localStorage.setItem(types.SET_NEWS, JSON.stringify(news))
    } catch (e) {
      console.log(e)
    }
  },
  [types.SET_SINGLE_NEW] (state, singleNew) {
    state.singleNew = singleNew
    // try {
    //   localStorage.setItem(types.SET_SINGLE_NEW, JSON.stringify(singleNew))
    // } catch (e) {
    //   console.log(e)
    // }
  }
}

export default mutations

mutations-types.js

export const SET_NEWS = 'SET_NEWS'
export const SET_SINGLE_NEW = 'SET_SINGLE_NEW'

getters.js

import * as types from './mutation-types'

export const news = (state) => {
  if (!state.news) {
    state.news = JSON.parse(localStorage.getItem(types.SET_NEWS)) ? JSON.parse(localStorage.getItem(types.SET_NEWS)) : {}
  }
  return state.news
}

export const singleNew = (state) => {
  return state.singleNew
}

index.js

import Vue from 'vue'
import Vuex from 'vuex'

import * as actions from './actions'
import * as state from './state'
import mutations from './mutations'
import * as getters from './getters'
import createLogger from 'vuex/dist/logger'

Vue.use(Vuex)

const debug = process.env.NODE_ENV !== 'production'

export default new Vuex.Store({
  actions,
  state,
  mutations,
  getters,
  strict: debug,
  plugins: debug ? [createLogger()] : []
})

你期待的结果是什么?实际看到的错误信息又是什么?

DetailLeft.vue
Getters 中'singleNew' 始终没值
图片描述

这里在控制台 手动commit 就可以
图片描述

阅读 3.2k
1 个回答

解决了 index.js 中

import * as state from './state'
写错了 换成
import state from './state'

就好了

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题