Repository: vuejs/vue
Pull request: fix(core): static trees should be cached on options (#6826)

<!--
Please make sure to read the Pull Request Guidelines:
https://github.com/vuejs/vue/blob/dev/.github/CONTRIBUTING.md#pull-request-guidelines
-->

<!-- PULL REQUEST TEMPLATE -->
<!-- (Update "[ ]" to "[x]" to check a box) -->

**What kind of change does this PR introduce?** (check at least one)

- [x] Bugfix
- [ ] Feature
- [ ] Code style update
- [ ] Refactor
- [ ] Build-related changes
- [ ] Other, please describe:

**Does this PR introduce a breaking change?** (check one)

- [ ] Yes
- [x] No

If yes, please describe the impact and migration path for existing applications:

**The PR fulfills these requirements:**

- [x] It's submitted to the `dev` branch for v2.x (or to a previous version branch), _not_ the `master` branch
- [x] When resolving a specific issue, it's referenced in the PR's title (e.g. `fix #xxx[,#xxx]`, where "xxx" is the issue number)
- [x] All tests are passing: https://github.com/vuejs/vue/blob/dev/.github/CONTRIBUTING.md#development-setup
- [x] New/updated tests are included

If adding a **new feature**, the PR's description includes:
- [ ] A convincing reason for adding this feature (to avoid wasting your time, it's best to open a suggestion issue first and wait for approval before working on it)

**Other information:**
#6826 

Changed files:
filename: src/core/instance/render-helpers/render-static.js
patch: @@ -11,8 +11,8 @@ export function renderStatic (
 ): VNode | Array<VNode> {
   // static trees can be rendered once and cached on the contructor options
   // so every instance shares the same cached trees
-  const renderFns = this.$options.staticRenderFns
-  const cached = renderFns.cached || (renderFns.cached = [])
+  const options = this.$options
+  const cached = options.cached || (options.cached = [])
   let tree = cached[index]
   // if has already-rendered static tree and not inside v-for,
   // we can reuse the same tree by doing a shallow clone.
@@ -22,7 +22,7 @@ export function renderStatic (
       : cloneVNode(tree)
   }
   // otherwise, render a fresh tree.
-  tree = cached[index] = renderFns[index].call(this._renderProxy, null, this)
+  tree = cached[index] = options.staticRenderFns[index].call(this._renderProxy, null, this)
   markStatic(tree, `__static__${index}`, false)
   return tree
 }

filename: test/unit/features/directives/once.spec.js
patch: @@ -335,6 +335,28 @@ describe('Directive v-once', () => {
       vm.ok = false // teardown component with v-once
     }).then(done) // should not throw
   })
+
+  // #6826
+  it('should render different component instances properly', done => {
+    const vm = new Vue({
+      components: {
+        foo: {
+          props: ['name'],
+          template: '<div v-once>{{ name }}</div>'
+        }
+      },
+      template: `
+        <div>
+          <foo name="a" v-once></foo>
+          <foo name="b" v-once></foo>
+        </div>
+      `
+    }).$mount()
+    waitForUpdate(() => {
+      expect(vm.$el.children[0].innerHTML).toBe('a')
+      expect(vm.$el.children[1].innerHTML).toBe('b')
+    }).then(done)
+  })
 })
 
 function expectTextContent (vm, text) {