CODEGURU

Реактивность и provide/inject

По умолчанию provide и inject во Vue не реактивны. Многим это не нравится. Многие хотели бы, чтобы они были реактивными. И хорошая новость в том, что добиться этого совсем несложно.

Но сначала подумайте

Описаные ниже техники нужно применять только в случае крайней необходимости. Не нужно использовать их как замену props и events.

Способ №1: с помощью поля data()

Любой объект, объявленный в поле data(), будет реактивным. Следовательно, его реактивность будет сохраняться, независимо от того, где он используется. Вы можете даже передать его в какой-то javascipt модуль за пределами вашего приложения, и любые изменения этого объекта там вызовут обновление в вашем приложении. Так что мы можем просто записать вот таким образом:

export default {
  data() {
    return {
      reactiveObject: {
        value: "Hello world"
      };
    }
  },
  provide() {
    return {
      reactive: this.reactiveObject
    };
  }
};

Способ №2: С помощью observable

Начиная с версии 2.6 во Vue доступна функция observable. Она позволяет создать реактивный объект. Собственно именно эту функцию Vue использует при добавлении реактивности к вашим данным в поле data(). Давайте перепишем предыдущий пример с использованием функции observable:

import Vue from "vue";
const reactiveObject = Vue.observable({value: "Hello world"});

export default {
  provide() {
    return {
      reactive: reactiveObject
    };
  }
};

Способ №3: Использовать специальный плагин

Участник команды разработки Vue Thorsten Lünborg написал плагин, добавляющий реактивность к provide. Исходный код доступен на github. Использовать его можно двумя способами.

Как плагин

Просто подключите его в файле main.js

import Vue from 'vue';
import ReactiveProvide from 'vue-reactive-provide';

Vue.use(ReactiveProvide);

Затем используйте в любом в компоненте, из которого хотите передать данные:

export default {
  reactiveProvide: {
    name: 'injectedName',
    include: ['reactive'],
  }

  data() {
    return {
      reactive: 'hello',
    };
  },
};

И в компоненте, в котором хотите получить данные:

export default {
  inject: ['injectedName']
};

Как миксин

Можно использовать как миксин. Тогда не нужно регистрировать плагин глобально.

import { ReactiveProvideMixin } from 'vue-reactive-provide'

export default {
  mixins: [
    ReactiveProvideMixin({
      name: 'injectedName',
      include: ['reactive'],
    })
  ],

  data() {
    return {
      reactive: 'hello',
    };
  },
};

Когда стоит использовать описанные способы

Помните, что лучше избегать добавления реактивности к provide/inject. В большинстве случаев прекрасно работает стандартная схема обмена данными: пропсы вниз, события наверх. Она не добавляет в код лишних усложнений и сохраняет читабельность кода.