<h3 dir="auto">Version</h3>
<p dir="auto">2.5.16</p>
<h3 dir="auto">Reproduction link</h3>
<p dir="auto"><a href="https://codesandbox.io/s/vn7jz1l1kl" rel="nofollow">https://codesandbox.io/s/vn7jz1l1kl</a></p>
<h3 dir="auto">Steps to reproduce</h3>
<p dir="auto">Click the button that says "refresh"</p>
<h3 dir="auto">What is expected?</h3>
<p dir="auto">Nothing should happen</p>
<h3 dir="auto">What is actually happening?</h3>
<p dir="auto">[Vue warn]: Duplicate presence of slot "default" found in the same render tree - this will likely cause render errors.</p>
<hr>
<p dir="auto">I have a component <code class="notranslate">B</code> which accepts a scopedSlot, and a component <code class="notranslate">A</code> which accepts a slot. <code class="notranslate">A</code> is passing in it's slot into the scopedSlot of <code class="notranslate">B</code></p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="&lt;template slot-scope=&quot;scope&quot;&gt;
          &lt;slot&gt;&lt;/slot&gt;
&lt;/template&gt;"><pre class="notranslate"><code class="notranslate">&lt;template slot-scope="scope"&gt;
          &lt;slot&gt;&lt;/slot&gt;
&lt;/template&gt;
</code></pre></div>
<p dir="auto">When the component <code class="notranslate">B</code> gets rerendered, I see this warning in the console. <code class="notranslate">B</code> passes a method to the scoped slot which will cause it to rerender when called.</p>
<h3 dir="auto">What problem does this feature solve?</h3>
<p dir="auto">Let me start by saying I love Vue. It is an awesome framework you guys have created, I enjoy using it, and it is at the very top of Frameworks of choice.</p>
<p dir="auto">But from day one there has been one small area where I found Vue lacking, this is in the Custom Directives department.</p>
<p dir="auto">I wasn't around for Vue 1, but from what I can gather a decision was made to "underpower" Custom Directives in favor of Components. And I agree, when you are developing applications Components is most likely all you need.</p>
<p dir="auto">The problem starts when you want to create plugins, especially UI plugins. I have created UI plugins in other Frameworks, specifically a Bootstrap native implementation, I have several features that are implemented with Custom Directives, I like how clean they are that way. But when I tried to achieve the same thing with Vue, well I got frustrated very quickly.</p>
<p dir="auto">Problem Number 1: We don't have a Vue instance. I wish we could create Custom Directives the Same way we create Custom Components. so we have an actual Vue Instance and we can use this. Right now you have to manually extract the directive bindings and store them in the in the element itself. It is not clean since I have to pass the el object around to have access to those properties. It is doable but not very clean.</p>
<p dir="auto">Problem Number 2: The update hook function it is not being called consistently. For instance, I have this: v-myDirective={foo: bar}; when bar changes the update method is not called, only when something in the DOM changes then update is called. This is super frustrating because many times you want to control the state of your directive based off a property value, but you have no consistent way to know if its value has changed. This is a real problem because there are things that cannot be done without a consistent way to know if a binded property has changed. I wish I could have a Vue instance and have watch methods to react to changes accordingly.</p>
<p dir="auto">I LOVE Vue, it is an awesome framework, I will continue to enjoy using it and to recommend it. But if this is improved I would have absolutely no reason to ever use any other framework.</p>
<p dir="auto">Thanks for the hard work and love that goes into Vue.</p>
<h3 dir="auto">What does the proposed API look like?</h3>
<p dir="auto">The API will basically be the same one we have for Custom Components. The example is silly, but I would love to be able to do something like this:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="Vue.directive('myDirective', {
  data: {
    el: null
  },
  props: ['foo', 'name'],
  bind (el, binding, vnode, oldVnode) {
    this.el = el
    //Bind
  },
  inserted (el, binding, vnode, oldVnode) {
    //Inserted
  },
  unbind (el, binding, vnode, oldVnode) {
    //Unbind
  },
  computed: {
    name () { return `My name is ${this.name}`}
  },
  watch: {
    name (value) { this.nameUpdated(value)}
  },
  methods: {
    nameUpdated (value) {
      this.$emit('nameUpdated', value)
    }
  }
})"><pre class="notranslate"><code class="notranslate">Vue.directive('myDirective', {
  data: {
    el: null
  },
  props: ['foo', 'name'],
  bind (el, binding, vnode, oldVnode) {
    this.el = el
    //Bind
  },
  inserted (el, binding, vnode, oldVnode) {
    //Inserted
  },
  unbind (el, binding, vnode, oldVnode) {
    //Unbind
  },
  computed: {
    name () { return `My name is ${this.name}`}
  },
  watch: {
    name (value) { this.nameUpdated(value)}
  },
  methods: {
    nameUpdated (value) {
      this.$emit('nameUpdated', value)
    }
  }
})
</code></pre></div>