VueJS - VueX 和 flash 消息

VueJS - VueX and flash messages

我使用 VueJS 2VueXNuxtJSVue -Snotify (artemsky/vue-snotify) 用于 flash 通知。

这可能不是 VueX 的正确使用,但我想 dispatch 在 try/catch.

中捕获的错误
try {
    throw new Error('test')
} catch (error) {
    this.$store.dispatch('errorHandler', error)
}

然后,如果有多个错误,使用 VueX 的调度应该使用带有循环的 Snotify-View 显示通知。

actions: {
    async errorHandler (error) {
        this.$snotify.error(error)
        // and if multiple errors, then while on error
    }
}

你怎么看以及如何在 VueX 中恢复 $snotify 的实例?

不好

我意识到 app 实例是在 Vue 存储的初始化中注入的。因此,您可以通过 this.app.$snotify 访问所需的 Snotify 服务。

此外,store 的另一个地方接收 Nuxt 上下文作为 第二个参数nuxtServerInit[2]。因此,您可以使用类似下一个 snippet.

的方式 access 访问 service
actions: {
    nuxtServerInit ({ state }, { app }) {
        // Workaround
        state.Snotify = app.$snotify // inject the context in the store
    },
    // Then, you can called as you want
    // There is not necessity to prefix the method with async keyword
    errorHandler ({ state }, message) {
        state.Snotify.error(message)
    }
}

在我看来,store 没有任何责任来处理数据的表示行为。因此,在这种情况下,store 的唯一目标是在组件之间传递消息,以 flash 消息 的形式显示在其他组件中在这种特殊情况下使用 Snotify。因此,总结一下我对声明的赞赏,我认为操作仅负责将 storestate 更改为 definition 的唯一真实来源

您必须使用 突变 并仅存储 对象 。然后,在您的视图或 HOC(高阶组件)中,使用可用的 Snotify 设置表示逻辑。为了支持我的回答,我强烈推荐 this library 因为它有更好的 APIVuex 而且它有一个很好的展示界面 (UI/UX)。免责声明:我并不是说这个比 Snotify 好,每一个都是为了满足略有不同的目的而构建的,至少就用户体验概念而言是这样。两者都很棒,可以用任何一种方式来说明这个用例。


我将更改您的第二个代码段:

state: {
    flash: null
}
mutations: {
    // Just extract message from the context that you are set before
    SET_ERROR (state, { message, title = 'Something happens!' }) {
        state.flash = { 
            type: 'error',
            title, 
            message
        }
    },
    FLUSH_FLASH (state) {
        state.flash = null
    }
}

另外,我会在一些 view/layout/component/HOC 上添加这个(我使用 SFC 最常用的方式)

<template>
    <vue-snotify />
    ...
</template>

<script>
   export default {
       // I use fetch because this is the lifecycle hook that executes 
       // immediately before page render is sure. And its purpose is to fill
       // the store before page render. But, to the best of my knowledge, 
       // this is the only place that you could use to trigger an immediately
       // executed function at the beginning of page render. However, also
       // you could use a middleware instead or "preferably use a wrapper 
       // component and get leverage of component lifecycle and use `mounted`" [4]
       fetch({ app, store }) {
           if (store.state.flash) {
               const { type, title, message: body } = store.state.flash
               const toast = app.$snotify[type](body, title)

               toast.on('destroyed', (t) => { store.commit('FLUSH_FLASH') })
           }
       },
       data: () => ({
           ...
       })
</script>

也许上面的代码对您来说功能不全,但我建议您应该测试类似的方法并满足您的需求。

编辑

我想指出我的答案的另一个改进,基于我上次与 组件生命周期 相关的更新。一开始,我其实想把消息放在组件 mounted 方法中,但后来我认为 Nuxt 页面有一个 different生命周期,直到我也看到这个 example and realize that Nuxt still been Vue on the background. Thus, any page actually is also a component by definition。然后你也可以做很多语义方法。

<template>
    <vue-snotify />
    ...
</template>

<script>
   export default {
       data: () => ({
           ...
       }),
       // Show the flash at the beginning when it's necessary
       mounted: {
           if (this.notification) {
               const { type, title, message: body } = this.notification
               const toast = this.$snotify[type](body, title)

               toast.on('destroyed', (t) => { this.$store.commit('FLUSH_FLASH') })
           }
       },
       computed: {
           notification () {
               return this.$store.state.flush
           }
       }
</script>

参考资料

[1] https://zendev.com/2018/06/07/async-data-options-in-vue-nuxt.html

[2]https://twitter.com/krutiepatel/status/1000022559184764930

[3] https://github.com/artemsky/vue-snotify/blob/master/example/src/App/app.ts

[4]https://medium.com/@fishpercolator/implementing-a-global-snackbar-in-nuxt-js-vuetify-using-vuex-a92b78e5651b