I have a component story that requires an API call performed by an ACTION from my Vuex store. However, the store can't be found by Storybook: Unhandled promise rejection TypeError: "this.$store is undefined"
.
I've tried to access the store through the created
and mounted
Vue lifecycle hooks but each of them returned undefined
.
My Vuex store is correctly working inside my app.
I run on storybook 5.0.1
and vuex 3.1.1
.
Here's my storybook config.js
:
// Taken from https://davidwalsh.name/storybook-nuxt & https://github.com/derekshull/nuxt-starter-kit-v2/blob/master/.storybook/config.js
import { addParameters, configure } from '@storybook/vue';
import { withOptions } from '@storybook/addon-options';
import { setConsoleOptions } from '@storybook/addon-console';
import { create } from '@storybook/theming';
import Vue from 'vue';
import VueI18n from 'vue-i18n';
// Vue plugins
Vue.use(VueI18n);
setConsoleOptions({
panelExclude: [],
});
// Option defaults:
addParameters({
options: {
/**
* show story component as full screen
* @type {Boolean}
*/
isFullScreen: false,
/**
* display panel that shows a list of stories
* @type {Boolean}
*/
showNav: true,
/**
* display panel that shows addon configurations
* @type {Boolean}
*/
showPanel: true,
/**
* where to show the addon panel
* @type {String}
*/
panelPosition: 'bottom',
/**
* sorts stories
* @type {Boolean}
*/
sortStoriesByKind: false,
/**
* regex for finding the hierarchy separator
* @example:
* null - turn off hierarchy
* /\// - split by `/`
* /\./ - split by `.`
* /\/|\./ - split by `/` or `.`
* @type {Regex}
*/
hierarchySeparator: /\/|\./,
/**
* regex for finding the hierarchy root separator
* @example:
* null - turn off multiple hierarchy roots
* /\|/ - split by `|`
* @type {Regex}
*/
hierarchyRootSeparator: /\|/,
/**
* sidebar tree animations
* @type {Boolean}
*/
sidebarAnimations: true,
/**
* enable/disable shortcuts
* @type {Boolean}
*/
enableShortcuts: true,
/**
* theme storybook, see link below
*/
theme: create({
base: 'light',
brandTitle: '',
brandUrl: '',
// To control appearance:
// brandImage: 'http://url.of/some.svg',
}),
},
});
const req = require.context('../src/components', true, /\.story\.js$/)
function loadStories() {
req.keys().forEach((filename) => req(filename))
}
configure(loadStories, module);
Here's my component's story:
import { storiesOf } from '@storybook/vue';
import { withReadme } from 'storybook-readme';
import { withKnobs } from '@storybook/addon-knobs';
import HandoffMainView from './HandoffMainView.vue';
import readme from './README.md';
storiesOf('HandoffMainView', module)
.addDecorator(withReadme([readme]))
.addDecorator(withKnobs)
.add('Default', () => {
/* eslint-disable */
return {
components: { HandoffMainView },
data() {
return {
isLoading: true,
component: {
src: '',
data: [],
},
};
},
template: '<handoff-main-view :component="component" />',
};
});
Here's my component:
<template>
<main class="o-handoff-main-view">
<div class="o-handoff-main-view__content">
<div
:class="[
'o-handoff-main-view__background',
background ? `o-handoff-main-view__background--${background}` : false
]"
>
<loader
v-if="isLoading"
:color='`black`'
class="o-handoff-main-view__loader"
/>
<div
v-else
class="o-handoff-main-view__ui-component"
:style="getUiComponentStyle"
>
<img
:src="uiComponent.src"
alt=""
>
<handoff-main-view-layer-list
:layers="uiComponent.data"
/>
</div>
</div>
</div>
<div class="o-handoff-main-view__controls">
<handoff-main-view-zoom-handler
:default-zoom-level="zoomLevel"
:on-change="updateZoomLevel"
/>
</div>
</main>
</template>
<script>
import { mapActions } from 'vuex';
import Loader from '../../01-atoms/Loader/Loader.vue';
import HandoffMainViewZoomHandler from '../HandoffMainViewZoomHandler/HandoffMainViewZoomHandler.vue';
import HandoffMainViewLayerList from '../HandoffMainViewLayerList/HandoffMainViewLayerList.vue';
export default {
components: {
Loader,
HandoffMainViewZoomHandler,
HandoffMainViewLayerList,
},
props: {
background: {
type: String,
default: 'damier',
},
component: {
type: Object,
required: true,
},
},
data() {
return {
isLoading: true,
zoomLevel: 1,
uiComponent: {
src: null,
}
};
},
mounted() {
this.setUiComponentImage();
},
methods: {
...mapActions('UiComponent', [
'ACTION_LOAD_SIGNED_URLS'
]),
async setUiComponentImage() {
const uiComponentImg = new Image();
const signedUrls = await this.ACTION_LOAD_SIGNED_URLS([this.component.id]);
uiComponentImg.onload = () => {
this.isLoading = false;
};
uiComponentImg.src = this.uiComponent.src;
},
},
};
</script>