Lifecycle hooks (Хуки жизненного цикла) — это очень важная часть любого компонента. Нам, нашему приложению, часто нужно знать что происходит с компонентом, когда он создан, смонтирован, обновлен или уничтожен.

В компоненте мы можем отлавливать эти события используя соответствующие методы, например:

  • created — экземпляр компонента создан
  • mounted — экземпляр компонента cмонтирован
  • updated — виртуальный DOM был обновлён из-за изменения данных
  • destroyed — экземпляр компонента уничтожен
  • и т.д. Документация

В коде нашего компонента это будет выглядеть так:

// MyComponent.vue
<template>
  <h1>Hello, {{ who }}</h1>
</template>

<script>
export default {
  name: 'MyComponent',
  data() {
    return {
      who: 'world'
    }
  },
  mounted() {
  // Сделаем что-то полезное после монтирования нашего компонента
  }
}
</script>

Хорошо. А что если родительскому компоненту нужно знать, что происходит в дочернем компоненте, например, что компонент обновился? В дочернем компоненте мы можем порождать событие, а на родительский компонент навесить слушателя. В коде нашего приложения это будет выглядеть так:

// Дочерний компонент ChildComponent.vue
<template>
  <div>
    <div>Count: {{ counter }}</div>
    <button @click="add">+1</button>
  </div>
</template>

<script>
export default {
  name: 'ChildComponent',
  data() {
    return {
      counter: 0
    }
  },
  updated() {
    this.$emit('updated')
  },
  methods: {
    add() {
      this.counter++
    }
  }
}
</script>

// Родительский компонент ParentComponent.vue
<template>
  <div>
    <ChildComponent @updated="usefulMethod"/>
  </div>
</template>

<script>
import ChildComponent from 'ChildComponent.vue'

export default {
  name: 'ParentComponent',
  components: {
    ChildComponent
  },
  data() {
    return {}
  },
  methods: {
    usefulMethod() {
    // Делаем что-то полезное по событию пришедшему из дочернего компонента
    }
  }
}
</script>

Отлично, при обновлении дочернего компонента родительский компонент отлавливает событие updated и выполняется метод usefulMethod().

Все круто! Но что делать, если нам нужно встроить сторонний компонент, скачанный с npm или git и сделать что-то полезное в родительском компоненте, например при его монтировании? Залезать в код стороннего компонента, в хуке mounted порождать событие,… Не самая хорошая идея! А что если я вам скажу, что этого делать не надо! Вместо этого мы можем просто слушать событие! Именем этого события будет имя хука жизненного цикла, но к нему нужно дописать префикс @hook: так-то так @hook:имя_хука_жизненного_цикла, например: @hook:mounted, @hook:updated или @hook:destroyed.

В коде выглядеть это будет примерно так:

// Родительский компонент ParentComponent.vue

<template>
  <div>
    <ThirdPartyComponent @hook:mounted="usefulMethod"/>
  </div>
</template>

<script>
import ThirdPartyComponent from 'vue-third-party-component' // Сторонний компонент

export default {
  name: 'ParentComponent',
  components: {
    ThirdPartyComponent
  },
  data() {
    return {}
  },
  methods: {
    usefulMethod() {
    // Делаем что-то полезное по хуку mounted произошедшему в стороннем компоненте
    }
  }
}
</script>

Как мне кажется, это очень полезный функционал для работы, как со своими, так и со сторонними компонентами. Надеюсь и вам он будет полезен. Немного странно, что в документации о нем нет ни слова и некоторые фичи можно узнать только читая исходный код.

Спасибо за прочтение. Читайте доку и исходники! И с наступающим новым 2020 годом!

Комментарии (7)


  1. coderisimo
    26.12.2019 13:48

    Спасибо! Интересно, почему подобное не презентуют в доках?


    1. valis
      26.12.2019 14:32

      Согласен. Сам только узнал, очень полезная фитча. Даже в случае использования своих компонентов позволяет сделать код чище.
      Надо будет завести issue странице документации на гитхабе.


  1. XAHTEP26
    26.12.2019 14:55
    +1

    Ну почему же ни слова. Пара слов есть. )
    vuejs.org/v2/guide/components-edge-cases.html#Programmatic-Event-Listeners

    А вообще то — чего нет в документации — это обычно возможности, которые не рекомендуется использовать, потому что они могут исчезнуть или измениться в очередной версии.


    1. Dimd13 Автор
      26.12.2019 16:10

      А вообще то — чего нет в документации — это обычно возможности, которые не рекомендуется использовать, потому что они могут исчезнуть или измениться в очередной версии.

      Эти события порождаются в библиотеке ядра vue, если точнее vue/src/core/instance/lifecycle.js:
      export function callHook (vm: Component, hook: string) {
        // #7573 disable dep collection when invoking lifecycle hooks
        pushTarget()
        const handlers = vm.$options[hook]
        const info = `${hook} hook`
        if (handlers) {
          for (let i = 0, j = handlers.length; i < j; i++) {
            invokeWithErrorHandling(handlers[i], vm, null, vm, info)
          }
        }
        if (vm._hasHookEvent) {
          vm.$emit('hook:' + hook) // <- вот тут вот
        }
        popTarget()
      }

      Не думаю, что события порожденные ядром для каждого компонента в вашем приложении не рекомендуются к использованию т.к.:
      — ядро само их использует и слушает
      — ну и из приведенного вами пункта документации можно, вывести что компонент порождает событие hook: имя_хука_жизненного_цикла, но вот о том что его можно подслушать на компоненте, увы не сказано.


      1. XAHTEP26
        26.12.2019 17:26

        Не думаю, что события порожденные ядром для каждого компонента в вашем приложении не рекомендуются к использованию

        Конечно вы можете их использовать, но разработчики оставляют за собой право в любой момент убрать их, переименовать или изменить логику их работы. Это конечно не критично, но надо об этом помнить. Подобных «скрытых» возможностей во Vue много и Эван сам писал что лучше воздержаться от использования их в коде. Например вот он пишет про использование _uid.

        ну и из приведенного вами пункта документации можно, вывести что компонент порождает событие hook: имя_хука_жизненного_цикла, но вот о том что его можно подслушать на компоненте, увы не сказано

        1. Компонент порождает события «hook:».
        2. События компонента можно слушать.
        Неужели вам надо сказать это еще более явно? )


  1. casusbelli-dn
    27.12.2019 11:06

    Как уживаются события хуков внутри компонента с событиями, определенными снаружи для того же хука?


    1. Dimd13 Автор
      27.12.2019 13:07

      Нормально, они изолированы экземпляром Vue