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())) +}