VueJS-VueX和Flash消息

pir*_*max 5 vue.js vuex nuxt.js

我使用VueJS 2VueXNuxtJSVue-Snotifyartemsky / vue-snotify)用于Flash通知。

这可能不是VueX的正确用法,但我想分派 try / catch中捕获的错误。

try {
    throw new Error('test')
} catch (error) {
    this.$store.dispatch('errorHandler', error)
}
Run Code Online (Sandbox Code Playgroud)

然后,如果有多个错误,则使用VueX进行的分派应使用Snotify-View循环显示通知。

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

您如何看待以及如何在VueX中恢复$ snotify实例?

mon*_*onk 5

我意识到该应用程序实例已注入Vue存储的初始化中。因此,您可以this.app.$snotify所需的位置访问Snotify服务。

同样,商店中接收Nuxt上下文作为第二个参数的另一个地方是nuxtServerInit[2]。因此,您可以使用下一个代码段访问服务

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

以我的观点,商店不负责处理数据的表示行为。因此,在这种情况下,商店的唯一目标是在要显示的组件之间传递消息,而在另一种情况下将其作为Flash消息传递Snotify。所以,来结束我的发言的赞赏,我认为行动只会有责任改变状态的的作为真理的唯一来源,通过定义

您必须改用变异,并且只存储Object。然后,在您的视图或HOC(高阶组件)中使用可用的Snotify设置表示逻辑。为了支持我的答案,我强烈建议您使用 库,因为它具有与Vuex进行通信的更好的API,并且还具有良好的表示接口(UI / UX)。免责声明:我并不是说这比Snotify更好,每一个都是为了满足稍有不同的目的而构建的,至少就UX概念而言。两者都很棒,可以用任何一种方式来说明此用例。


我将为您更改第二个片段:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

而且,我将在某些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>
Run Code Online (Sandbox Code Playgroud)

也许上面的代码对您来说并不完全起作用,但是我建议您应该测试一种类似的方法并满足您的需求。

编辑

我想根据与组件生命周期相关的最新更新指出对我的答案的另一种改进。开始时,我实际上想将消息放入component mounted方法中,但是后来我认为Nuxt页面具有不同的生命周期,直到我看到此示例并意识到Nuxt在后台仍然是Vue。因此,根据定义,任何页面实际上也是一个组件。然后,您也可以执行很多语义方法。

<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>
Run Code Online (Sandbox Code Playgroud)

参考文献

[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