a7dc
a7dc

Reputation: 3426

Can't read from Vuex store in Storybook

I'm using Storybook with vue create, and I'm trying to read state from the store but I'm getting the following error:

Cannot read property 'state' of undefined
TypeError: Cannot read property 'state' of undefined
    at VueComponent.translations (http://localhost:6006/main.08c5b1c8a108e2d2d34c.bundle.js:161:26)
    at Watcher.get (http://localhost:6006/vendors~main.08c5b1c8a108e2d2d34c.bundle.js:86420:25)
    at Watcher.evaluate (http://localhost:6006/vendors~main.08c5b1c8a108e2d2d34c.bundle.js:86525:21)
    at VueComponent.computedGetter [as translations] (http://localhost:6006/vendors~main.08c5b1c8a108e2d2d34c.bundle.js:86775:17)
    at Object.get (http://localhost:6006/vendors~main.08c5b1c8a108e2d2d34c.bundle.js:84041:20)
    at Proxy.render (http://localhost:6006/main.08c5b1c8a108e2d2d34c.bundle.js:895:37)
    at VueComponent.Vue._render (http://localhost:6006/vendors~main.08c5b1c8a108e2d2d34c.bundle.js:85489:22)
    at VueComponent.updateComponent (http://localhost:6006/vendors~main.08c5b1c8a108e2d2d34c.bundle.js:86007:21)
    at Watcher.get (http://localhost:6006/vendors~main.08c5b1c8a108e2d2d34c.bundle.js:86420:25)
    at new Watcher (http://localhost:6006/vendors~main.08c5b1c8a108e2d2d34c.bundle.js:86409:12)

My HotDescription component looks like:

<template>
    <div class="hot-description">
        <SvgIcon iconId="icon-hot" class="icon-hot"/>
        <span>{{translations.ui.hotMessage}}</span>
    </div>
</template>

<script>

export default {
    name: 'HotDescription',
    computed: {
        translations() {
            return this.$store.state.translations
        }
    }
}
</script>

<style scoped lang="scss">

.hot-description {
    font-size: 14px;
    color: $hot-description-color;
    padding: 2%;
    border-top: 1px solid $hot-description-border-color;
    text-align: center;
}

.icon-hot {
    width: 14px;
    height: 14px;
    margin: 0 3px 3px;
}
</style>

Inside .storybook I have two files:

main.js:

const path = require('path');

module.exports = {
  stories: ['../stories/**/*.stories.js'],
  addons: ['@storybook/addon-actions', '@storybook/addon-links'],
  webpackFinal: async (config, { configType }) => {
    // `configType` has a value of 'DEVELOPMENT' or 'PRODUCTION'
    // You can change the configuration based on that.
    // 'PRODUCTION' is used when building the static version of storybook.

    // Make whatever fine-grained changes you need
    config.module.rules.push({
      test: /\.scss$/,
      use: ['style-loader', 'css-loader', 
        {
          loader: 'sass-loader',
          options: {
            prependData: `@import "src/project/betpawa/vars.scss"; @import "src/project/common/mixins.scss"; @import "src/styles/styles.scss";`
          }
        }
    ],
      include: path.resolve(__dirname, '../'),
    });

    // Return the altered config
    return config;
  },
};

And preview.js:

import { configure } from '@storybook/vue';

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

// Import your global components.
import HotDescription from '../src/components/HotDescription.vue';

// Install Vue plugins.
Vue.use(Vuex);

// Register global components.
Vue.component('HotDescription', HotDescription);

configure(require.context('../stories', true, /\.stories\.js$/), module);

And then the stories (stories/1-Button.stories.js):

import Test from '../src/components/Test'
import HotDescription from '../src/components/HotDescription'

export default {
    title: 'Button',
    component: Test
}

export const C = () => ({
    components: { HotDescription },
    template: '<HotDescription />'
})

It's mounted in src/main.js:

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import Vuex from 'vuex'

import App from './App'
import router from './router'
import store from './store/store'
import './js/directives'
import './js/plugins'
import './js/globalComponents'
import './js/android'
import './js/filters'
import './js/polyfills'

Vue.config.productionTip = false
Vue.use(Vuex)

const app = new Vue({
    el: '#app',
    store,
    router,
    components: { App },
    template: '<App/>',
    mq: {
        isSmallest: '(max-width: 220px)',
        isVerySmall: '(max-width: 280px)',
        isXXSmall: '(max-width: 340px)',
        isXSmall: '(max-width: 380px)',
        isSmall: '(max-width: 767px)',
        isMedium: '(min-width: 768px)',
        isLarge: '(min-width: 980px)',
        isHighRes: '(-webkit-min-device-pixel-ratio: 2), (min-device-pixel-ratio: 2)' // , (min-resolution: 192dpi)
    }
})

export default app

Any ideas what I'm doing wrong?

Storybook itself loads up, and components work without state, it's just anything that requires vuex doesn't work...

Upvotes: 0

Views: 3110

Answers (2)

Rodzilla
Rodzilla

Reputation: 215

FYI, I was able to get this working by adding the following to preview.js:

import Vuex from 'vuex';
import Vue from 'vue'
import store from '../src/store/store'

Vue.use(Vuex);
Vue.prototype.$store = store;

Upvotes: 4

Dan
Dan

Reputation: 63129

EDIT: After browsing the Storybook docs, I see this:

You might be using global components or vue plugins such as vuex, in that case you’ll need to register them in this preview.js file

Their example code looks like this:

// Import Vue plugins
import Vuex from 'vuex';

// Install Vue plugins.
Vue.use(Vuex);

Have you done this in preview.js? (Keep in mind I've never looked at Storybook before, just browsing the docs.)


Original answer

The store has no default export, so that import syntax won't work. You could grab the named export:

import { store } from './store'

Or you could change the store to use a default export:

export default new Vuex.Store({
  state: {
    count: 1
  },
})

Upvotes: 2

Related Questions