Repository: vuejs/vue
Pull request: feat(functional): add scopedSlots to context in functional components

Related #5381

We discussed this being added to 2.6.
It is nothing new, as `scopedSlots` already exist on `data`. The only reasons to add it are convenience and consistency with `slots` (although `slots` is a function).
If you have arguments for or against this feature, please share them 🙂 

<!--
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)

- [ ] Bugfix
- [x] 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)
- [ ] 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:**


Changed files:
filename: src/core/vdom/create-functional-component.js
patch: @@ -48,6 +48,7 @@ export function FunctionalRenderContext (
   this.children = children
   this.parent = parent
   this.listeners = data.on || emptyObject
+  this.scopedSlots = data.scopedSlots || emptyObject
   this.injections = resolveInject(options.inject, parent)
   this.slots = () => resolveSlots(children, parent)
 

filename: test/unit/features/options/functional.spec.js
patch: @@ -79,6 +79,23 @@ describe('Options functional', () => {
     document.body.removeChild(vm.$el)
   })
 
+  it('should expose data.scopedSlots as scopedSlots', () => {
+    const vm = new Vue({
+      template: '<div><wrap><p slot-scope="a">{{ a }}</p></wrap></div>',
+      components: {
+        wrap: {
+          functional: true,
+          render (h, { scopedSlots, data }) {
+            expect(data.scopedSlots).toBe(scopedSlots)
+            return data.scopedSlots.default('a')
+          }
+        }
+      }
+    }).$mount()
+
+    expect(vm.$el.textContent).toBe('a')
+  })
+
   it('should support returning more than one root node', () => {
     const vm = new Vue({
       template: `<div><test></test></div>`,

filename: types/options.d.ts
patch: @@ -1,5 +1,5 @@
 import { Vue, CreateElement, CombinedVueInstance } from "./vue";
-import { VNode, VNodeData, VNodeDirective } from "./vnode";
+import { VNode, VNodeData, VNodeDirective, ScopedSlot } from "./vnode";
 
 type Constructor = {
   new (...args: any[]): any;
@@ -140,6 +140,7 @@ export interface RenderContext<Props=DefaultProps> {
   data: VNodeData;
   parent: Vue;
   listeners: { [key: string]: Function | Function[] };
+  scopedSlots: { [key: string]: ScopedSlot };
   injections: any
 }
 

filename: types/test/options-test.ts
patch: @@ -381,6 +381,7 @@ Vue.component('functional-component', {
     context.slots();
     context.data;
     context.parent;
+    context.scopedSlots;
     context.listeners.click;
     return createElement("div", {}, context.children);
   }