Storybook中通过setup函数使用Vuex并注入自定义store的方法
核心结论
完全支持为单个Story配置专属自定义Vuex store,无需依赖全局preview.js的注入逻辑,核心原理是利用Vue的provide/inject机制,在Story的装饰器层提供与组件useStore()调用时匹配的注入键对应的store实例即可。
前置注意:注入键必须完全匹配
你在组件中调用useStore()时传的参数,决定了provide时需要使用的键,二者必须完全一致,否则组件无法拿到自定义store:
- 如果组件写的是无参的
useStore():需要从vuex导入内部默认的storeKey作为provide的键import { storeKey } from 'vuex' - 如果组件写的是自定义键的
useStore(key)(和你全局app.use(store, key)使用的是同一个自定义key):直接导入项目里导出的这个key作为provide的键即可import { key } from '@/store'
具体实现方案
方案1:单Story独立配置装饰器
适合仅少量Story需要自定义store的场景,写法如下:
// 组件对应的Story文件,如 src/components/MyComponent.stories.js import { h, provide } from 'vue' import { createStore } from 'vuex' // 按组件实际的useStore调用情况导入对应的键 import { storeKey } from 'vuex' // 无参useStore用这个 // import { key } from '@/store' // 自定义key的useStore用这个 import MyComponent from './MyComponent.vue' export default { title: 'Components/MyComponent', component: MyComponent } // 默认Story(保留全局preview注入的话,会使用全局store) export const Default = {} // 自定义store的专属Story export const WithCustomStore = { // Story本身的props、args正常编写即可,会自动透传 args: { title: '测试标题' }, decorators: [ (storyFn) => ({ setup() { // 创建完全自定义的store,配置规则和普通Vuex store完全一致 const customStore = createStore({ state: () => ({ // 按需编写组件依赖的state userName: 'Story专属测试用户', count: 100 }), // 按需补充mutations、actions、getters、modules即可 }) // 将自定义store provide给组件,键必须和useStore调用的键完全匹配 provide(storeKey, customStore) // 对应无参useStore的情况 // provide(key, customStore) // 对应自定义key的情况 return {} }, render() { // 渲染原Story,自动透传所有args、props配置 return h(storyFn()) } }) ] }
方案2:封装可复用的store注入装饰器
适合多个Story都需要自定义store的场景,避免重复编写逻辑:
- 在
.storybook目录下编写公共装饰器:
// .storybook/withVuexStore.js import { h, provide } from 'vue' import { createStore } from 'vuex' // 按项目实际情况导入对应的键 import { storeKey } from 'vuex' // import { key } from '@/store' /** * 自定义store注入装饰器 * @param {Object} storeConfig 自定义的Vuex store配置 */ export const withVuexStore = (storeConfig) => (storyFn) => ({ setup() { const customStore = createStore(storeConfig) provide(storeKey, customStore) // 替换为你实际使用的注入键 return {} }, render() { // 渲染原Story,完整保留原有args、props配置 return h(storyFn()) } })
- 在Story中直接调用该装饰器即可:
export const WithCustomCount = { decorators: [ withVuexStore({ state: () => ({ count: 999 }), // 其他store配置按需编写 }) ] }
常见问题说明
- 如果你保留了
preview.js里的全局app.use(store, key)逻辑,装饰器里provide的store会优先级更高,覆盖全局注入的store,组件会优先拿到自定义store,不会产生冲突。 - 如果想完全脱离全局注入,可以直接删掉
preview.js里的全局store注入代码,所有Story的store都通过装饰器独立配置,完全不会互相污染。
内容的提问来源于stack exchange,提问作者Lyokolux
相关产品推荐
相关产品推荐

