본문 바로가기

Java Scripts/Vue.js

Vuex : Success & Error Notifications

728x90

Success & Error Notifications

  • Add notifications to our Vuex store when things like errors and successful actions occur.
  • 오류나 성공적인 작업이 발생하면 Vuex 스토어에 알림을 추가하세요.
  • Display those notifications within our UI.
  • UI 내에 해당 알림을 표시합니다.

 

Problem: Need to Log and Display Notifications

need a way to log them so we can share that state across our application.

애플리케이션 전체에서 해당 상태를 공유할 수 있도록 로그하는 방법이 필요합니다.

Solution: A Vuex Module

New notification module that stores the State for our app’s success and error notifications.. then display those notifications to our user.

app’s success 및 error notifications에 대한 State를 저장하는 새로운 알림 모듈. 그런 다음 해당 알림을 사용자에게 표시합니다.

 

/src/store/modules/notification.js

be able to add a notification into it, and we also want the ability to remove a notification from it.

여기에 알림을 추가할 수 있고 알림을 제거하는 기능도 원합니다.

    export const namespaced = true
    
    export const state = {
      notifications: []
    }

 

/src/store/modules/notification.js

The PUSH Mutation pushes a new notification that it receives as a payload into the notifications State array.

PUSH Mutation은 페이로드로 수신한 새 알림을 알림 State 배열에 푸시합니다.

It adds an id property to the notification, using the nextId variable, which can make a unique id for each new notification.

각각의 새 알림에 대해 고유한 ID를 만들 수 있는 nextId 변수를 사용하여 알림에 id 속성을 추가합니다.

The DELETE Mutation receives a notificationToRemove payload, which is used to filter the notifications and remove that specific notification from the State.

DELETE Mutation은 알림을 필터링하고 State에서 해당 특정 알림을 제거하는 데 사용되는notificationToRemove 페이로드를 수신합니다.

    let nextId = 1
    
    export const mutations = {
      PUSH(state, notification) {
        state.notifications.push({
          ...notification,
          id: nextId++
        })
      },
      DELETE(state, notificationToRemove) {
        state.notifications = state.notifications.filter(
          notification => notification.id !== notificationToRemove.id
        )
      }
    }

 

/src/store/modules/notification.js

Dedicated Actions that can commit these Mutations

이러한 Mutations를 커밋할 수 있는 전용 Actions 

    ...
    export const actions = {
      add({ commit }, notification) {
        commit('PUSH', notification)
      },
      remove({ commit }, notificationToRemove) {
        commit('DELETE', notificationToRemove)
      }
    }

 

/src/store/store.js

Add this module to our store.js 

이 모듈을 store.js에 추가하세요.

    import * as notification from '@/store/modules/notification.js' // <-- import it
    
    export default new Vuex.Store({
      modules: {
        user,
        event,
        notification // <-- add it here
      },

 

Adding Error Notifications

/src/store/modules/event.js

Dispatch the add Action that lives in our notification module such that this error can be added to notifications State.

이 오류가 알림 State에 추가될 수 있도록 알림 모듈에  add Action을 전달합니다.

     ...
        .catch(error => {
          const notification = {  // creating a notification object
            type: 'error',
            message: 'There was a problem fetching events: ' + error.message
          }
          dispatch('notification/add', notification, { root: true })
        })

notification module is namespaced, hence dispatch the add Action with 'notification/add'.

알림 모듈은 네임스페이스가 있으므로 'notification/add'를 사용하여 추가 작업을 전달합니다.

third argument { root: true } tells dispatch to look for a notification/add action at the root of our store.

세 번째 인수 { root: true }는 디스패치에게 store 루트에서 알림/추가 작업을 찾도록 지시합니다.

instead of just looking for it inside the module we’re currently in.

우리가 현재 속해 있는 모듈 내에서 찾는 대신에 말이죠.

 

 

More Error Notifications

/src/store/modules/event.js

Have the fetchEvent Action.

fetchEvent Action이 있습니다.

Get an error when our app tries to fetchEvents or fetchEvent, those errors will be added into our notification module’s State. 앱이 fetchEvents 또는 fetchEvent를 시도할 때 오류가 발생하면 해당 오류가 알림 모듈의 State에 추가됩니다.

 

    ...
        .catch(error => {
          const notification = {
            type: 'error',
            message: 'There was a problem fetching an event: ' + error.message
          }
          dispatch('notification/add', notification, {
            root: true
          })
        })
    ...

 

Success and Error Notifications

Add some notification-based code for both error notifications and also success notifications.

오류 알림과 성공 알림 모두에 대한 일부 알림 기반 코드를 추가합니다.

 

/src/store/modules/event.js

Creating a notification object and passing it in as the payload when we dispatch the notification module’s add action.

알림 객체를 생성하고 알림 모듈의 add action.을 전달할 때 이를 페이로드로 전달합니다.

Note that we added dispatch in the first argument from the context object, so we could use it within the Action: { commit, dispatch }. 컨텍스트 객체의 첫 번째 인수에 디스패치를 ​​추가했기 때문에 Action 내에서 사용할 수 있습니다.

    createEvent({ commit, dispatch }, event) {
      return EventService.postEvent(event)
        .then(() => {
          commit('ADD_EVENT', event)
          const notification = {
            type: 'success',
            message: 'Your event has been created!'
          }
          dispatch('notification/add', notification, { root: true })
        })
    }

 

/src/store/modules/event.js

Throw the error so that we can propagate it up to our component (EventCreate).

오류를 component(EventCreate)에 전파할 수 있도록 오류를 발생시킵니다.

In EventCreate component, if that error was caught, we won’t $router.push to a new route, and we won’t clear out this.event. 

EventCreate component에서 해당 오류가 발견되면 $router.push를 새 경로로 푸시하지 않으며 this.event를 지우지 않습니다.

    ...
          dispatch('notification/add', notification, { root: true })
        })
        .catch(error => {
          const notification = {
            type: 'error',
            message: 'There was a problem creating your event: ' + error.message
          }
          dispatch('notification/add', notification, { root: true })
          throw error
        })
      
    }
    
    
   // from EventCreate.
   
        createEvent() {
      this.$store.dispatch('event/createEvent', this.event).then(() => {
        this.$router.push({
          name: 'event-show',
          params: { id: this.event.id }
        })
        this.event = this.createFreshEventObject()
      })
      .catch(() => { // <-- delete
        console.log('There was a problem creating your event') // <-- delete
      })// <-- delete
    
        createEvent() {
      this.$store.dispatch('event/createEvent', this.event).then(() => {
        this.$router.push({
          name: 'event-show',
          params: { id: this.event.id }
        })
        this.event = this.createFreshEventObject()
      })
      .catch(() => { // <-- delete
        console.log('There was a problem creating your event') // <-- delete
      })// <-- delete

 

Displaying our Notifications

  1. NotificationBar.vue will display the notification message itself. NotificationBar.vue는 알림 메시지 자체를 표시합니다.
  2. NotificationContainer.vue will create a NotificationBar for every notification in the State. NotificationContainer.vue는 State의 모든 알림에 대해NotificationBar를 생성합니다.

 

/src/components/NotificationBar.vue

printing out the notification.message, which this component is receiving as a prop.

이 구성 요소가 prop으로 수신하는notification.message를 인쇄합니다.

    <template>
      <div class="notification-bar">
        <p>{{ notification.message }}</p>
      </div>
    </template>
    
    <script>
    export default {
      props: {
        notification: {
          type: Object,
          required: true
        }
      }
    }
    </script>
    
    <style scoped>
    .notification-bar {
      margin: 1em 0 1em;
    }
    </style>

Add a computed property that uses the type of our notification to create a class name.

class name을 생성하기 위해 알림 유형을 사용하는 computed 속성을 추가합니다.

"-text-error" or "-text-success" depending on the type of notification prop object.

알림 prop  개체의 유형에 따라 "-text-error" 또는 "-text-success"입니다.

    ...
      computed: {
        notificationTypeClass() {
          return `-text-${this.notification.type}`
        }

 

v-bind notificationTypeClass to a class on the div.

notificationTypeClass를 div의 클래스에 바인딩합니다.

      <div class="notification-bar" 
            :class="notificationTypeClass"> <-- binding computed property here
        <p>{{ notification.message }}</p>
      </div>

 

Nesting into NotificationContainer

create NotificationContainer, and use it to create our NotificationBar components.

NotificationContainer를 생성하고 이를 사용하여 NotificationBar components를 생성합니다.

 

/src/components/NotificationContainer.vue

Using v-for to create a NotificationBar for each of the notifications that are in our notification module’s State.

v-for를 사용하여 알림 모듈의 State에 있는 각 알림에 대한NotificationBar를 생성합니다.

    <template>
      <div class="notification-container">
        <NotificationBar
          v-for="notification in notifications"
          :key="notification.id"
          :notification="notification"
        />
      </div>
    </template>
    
    <script>
    import NotificationBar from './NotificationBar'
    import { mapState } from 'vuex'
    
    export default {
      components: { NotificationBar },
      computed: mapState('notification', ['notifications'])
     }
    </script>
    
    <style scoped>
    .notification-container {
      position: fixed;
      bottom: 0;
    }
    </style>

Adding NotificationContainer to our App.js

Import NotificationContainer into the root component of our app: App.vue to  display notifications globally, on the app level.

알림 컨테이너를 앱의 루트 component 인 App.vue로 가져와서 앱 수준에서 전역적으로 알림을 표시합니다.

 

/src/App.vue

    <template>
      <div id="app">
        <NavBar/>
        <NotificationContainer/>
        <router-view :key="$route.fullPath" />
      </div>
    </template>
    
    <script>
    import NavBar from '@/components/NavBar.vue'
    import NotificationContainer from '@/components/NotificationContainer.vue'
    
    export default {
      components: {
        NavBar,
        NotificationContainer
      }
    }
    </script>

Removing Notifications

Show the notification to the user for a set amount of time, such as 5 seconds. And when that 5 seconds is up, the notification can delete itself..

5초 등 설정된 시간 동안 사용자에게 알림을 표시합니다. 그리고 5초가 지나면 알림이 자동으로 삭제될 수 있습니다.

 

/src/components/NotificationBar.vue

Using mapActions to give our NotificationBar the ability to dispatch the remove Action.

mapActions를 사용하여 알림바에 제거 작업을 전달하는 기능을 제공합니다.

    <script>
    import { mapActions } from 'vuex'
    ...
      props: {
        notification: {
          type: Object,
          required: true
        },
    ...
      methods: mapActions('notification', ['remove'])
    ...
    </script>

 

/src/components/NotificationBar.vue

Trigger "this.remove(this.notification)" 5 seconds after the notification is displayed.

알림이 표시된 후 5초 후에 "this.remove(this.notification)"를 트리거합니다.

In other words, 5 seconds after the NotificationBar component is mounted to the DOM.

즉, NotificationBar 컴포넌트가 DOM에 마운트되고 5초가 지난 시점입니다.

    <script>
    ...
      data() {
        return {
          timeout: null
        }
      },
      mounted() {
        this.timeout = setTimeout(() => this.remove(this.notification), 5000)
      },
      methods: mapActions('notification', ['remove'])
    }
    </script>

 

/src/components/NotificationBar.vue

Clear the setTimeout just before this component is destroyed.

이 구성 요소가 삭제되기 직전에 setTimeout을 지웁니다.

Avoid a memory leak by not leaving the setTimeout running if this component isn’t being actively displayed

이 구성 요소가 활발하게 표시되지 않는 경우 setTimeout을 실행 상태로 두지 않음으로써 메모리 누수를 방지하세요.

    ...
      beforeDestroy() {
        clearTimeout(this.timeout)
      },
    ...

 

Resources

https://medium.com/outsystems-experts/beyond-memory-leaks-in-javascript-d27fd48ae67e

 

Beyond Memory Leaks in JavaScript

Memory leaks are like that pimple you have on your nose with prom night coming. You know that they exist and they’re not going anywhere…

medium.com

https://github.com/Code-Pop/real-world-vue/releases/tag/lesson15-notifications-finish

 

Release lesson15-notifications-finish · Code-Pop/real-world-vue

Merge remote-tracking branch 'origin/master'

github.com

 

'Java Scripts > Vue.js' 카테고리의 다른 글

Vue : Slots: Techniques  (0) 2022.05.15
Vue - Global and Per-Route Guards  (0) 2022.05.14
Vuex - Modules  (0) 2022.05.04
Vue : In-Component Route Guards  (0) 2022.05.01
Vue : Flash Messages  (0) 2022.05.01