From 56c3646838f17a179ffef25fd71809ce83ae5fd9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9C=88=E8=90=BD=E9=9F=B3=E9=98=91?= <424532913@qq.com>
Date: Thu, 18 Nov 2021 14:49:33 +0800
Subject: [PATCH] feat(vue): add injectionCleaner to FormProvider (#2449)
---
packages/vue/src/__tests__/form.spec.ts | 57 ++++++++++++++++++-
packages/vue/src/components/FormProvider.ts | 17 +++++-
packages/vue/src/hooks/useInjectionCleaner.ts | 7 +++
3 files changed, 78 insertions(+), 3 deletions(-)
create mode 100644 packages/vue/src/hooks/useInjectionCleaner.ts
diff --git a/packages/vue/src/__tests__/form.spec.ts b/packages/vue/src/__tests__/form.spec.ts
index 1857e7e9f3b..a8d62f869b5 100644
--- a/packages/vue/src/__tests__/form.spec.ts
+++ b/packages/vue/src/__tests__/form.spec.ts
@@ -1,5 +1,5 @@
import Vue from 'vue'
-import { render } from '@testing-library/vue'
+import { render, fireEvent } from '@testing-library/vue'
import { createForm } from '@formily/core'
import {
FormProvider,
@@ -9,7 +9,7 @@ import {
VoidField,
} from '../vue2-components'
import { defineComponent } from 'vue-demi'
-import { useParentForm } from '../hooks'
+import { useParentForm, useField } from '../hooks'
import { h } from 'vue-demi'
Vue.component('FormProvider', FormProvider)
@@ -18,6 +18,28 @@ Vue.component('ObjectField', ObjectField)
Vue.component('VoidField', VoidField)
Vue.component('Field', Field)
+const Input = defineComponent({
+ props: ['value'],
+ setup(props, { attrs, listeners }) {
+ const fieldRef = useField()
+ return () => {
+ const field = fieldRef.value
+ return h('input', {
+ class: 'test-input',
+ attrs: {
+ ...attrs,
+ value: props.value,
+ 'data-testid': field.path.toString(),
+ },
+ on: {
+ ...listeners,
+ input: listeners.change,
+ },
+ })
+ }
+ },
+})
+
test('render form', () => {
const form = createForm()
render({
@@ -72,3 +94,34 @@ test('useParentForm', () => {
expect(queryByTestId('222').textContent).toBe('Form')
expect(queryByTestId('333').textContent).toBe('Form')
})
+
+test('useInjectionCleaner', async () => {
+ const form = createForm()
+
+ const { getByTestId } = render(
+ defineComponent({
+ name: 'TestComponent',
+ setup() {
+ return {
+ form,
+ Input,
+ }
+ },
+ template: `
+
+
+
+
+
+
+ `,
+ })
+ )
+ expect(form.mounted).toBeTruthy()
+ expect(form.query('inner').take().mounted).toBeTruthy()
+ expect(form.query('parent.outer').take().mounted).toBeTruthy()
+ await fireEvent.update(getByTestId('parent.outer'), '123')
+ expect(form.getValuesIn('parent.outer')).toBe('123')
+ await fireEvent.update(getByTestId('inner'), '123')
+ expect(form.getValuesIn('inner')).toBe('123')
+})
diff --git a/packages/vue/src/components/FormProvider.ts b/packages/vue/src/components/FormProvider.ts
index 465e1f56b49..69b8a96e240 100644
--- a/packages/vue/src/components/FormProvider.ts
+++ b/packages/vue/src/components/FormProvider.ts
@@ -1,7 +1,15 @@
import { provide, defineComponent, watch } from 'vue-demi'
-import { FormSymbol } from '../shared/context'
+import {
+ FormSymbol,
+ FieldSymbol,
+ SchemaMarkupSymbol,
+ SchemaSymbol,
+ SchemaExpressionScopeSymbol,
+ SchemaOptionsSymbol,
+} from '../shared/context'
import { IProviderProps } from '../types'
import { useAttach } from '../hooks/useAttach'
+import { useInjectionCleaner } from '../hooks/useInjectionCleaner'
import h from '../shared/h'
import { Fragment } from '../shared/fragment'
@@ -25,6 +33,13 @@ export default defineComponent({
)
provide(FormSymbol, formRef)
+ useInjectionCleaner([
+ FieldSymbol,
+ SchemaMarkupSymbol,
+ SchemaSymbol,
+ SchemaExpressionScopeSymbol,
+ SchemaOptionsSymbol,
+ ])
return () => h(Fragment, { attrs }, slots)
},
diff --git a/packages/vue/src/hooks/useInjectionCleaner.ts b/packages/vue/src/hooks/useInjectionCleaner.ts
new file mode 100644
index 00000000000..7b72d640890
--- /dev/null
+++ b/packages/vue/src/hooks/useInjectionCleaner.ts
@@ -0,0 +1,7 @@
+import { InjectionKey, provide, Ref, ref } from 'vue-demi'
+
+export const useInjectionCleaner = (
+ injectionKeys: InjectionKey[>[]
+) => {
+ injectionKeys.forEach((key) => provide(key, ref()))
+}
]