From a306b1b0047ec82eaf727a6e380856de077c4fbe Mon Sep 17 00:00:00 2001 From: Abdelrahman Awad Date: Mon, 19 Apr 2021 01:16:26 +0200 Subject: [PATCH] fix: minor perf enhancement by lazy evaulation of slot props --- packages/vee-validate/src/ErrorMessage.ts | 16 +++++++++------ packages/vee-validate/src/Field.ts | 25 +++++++++++------------ packages/vee-validate/src/Form.ts | 11 +++++----- packages/vee-validate/src/utils/vnode.ts | 14 +++++++++++-- 4 files changed, 40 insertions(+), 26 deletions(-) diff --git a/packages/vee-validate/src/ErrorMessage.ts b/packages/vee-validate/src/ErrorMessage.ts index 0d7804f48..576ab1090 100644 --- a/packages/vee-validate/src/ErrorMessage.ts +++ b/packages/vee-validate/src/ErrorMessage.ts @@ -19,17 +19,21 @@ export const ErrorMessage = defineComponent({ return errors?.value[props.name]; }); + function slotProps() { + return { + message: message.value, + }; + } + return () => { // Renders nothing if there are no messages if (!message.value) { return undefined; } - const children = normalizeChildren(ctx, { - message: message.value, - }); - const tag = (props.as ? resolveDynamicComponent(props.as) : props.as) as string; + const children = normalizeChildren(tag, ctx, slotProps); + const attrs = { role: 'alert', ...ctx.attrs, @@ -37,13 +41,13 @@ export const ErrorMessage = defineComponent({ // If no tag was specified and there are children // render the slot as is without wrapping it - if (!tag && children?.length) { + if (!tag && (Array.isArray(children) || !children) && children?.length) { return children; } // If no children in slot // render whatever specified and fallback to a with the message in it's contents - if (!children?.length) { + if ((Array.isArray(children) || !children) && !children?.length) { return h(tag || 'span', attrs, message.value); } diff --git a/packages/vee-validate/src/Field.ts b/packages/vee-validate/src/Field.ts index dce595f71..8f92e8c75 100644 --- a/packages/vee-validate/src/Field.ts +++ b/packages/vee-validate/src/Field.ts @@ -161,7 +161,17 @@ export const Field = defineComponent({ return attrs; }); - const slotProps = computed(() => { + if ('modelValue' in props) { + const modelValue = toRef(props, 'modelValue'); + watch(modelValue, newModelValue => { + if (newModelValue !== applyModifiers(value.value, props.modelModifiers)) { + value.value = newModelValue; + validateField(); + } + }); + } + + function slotProps() { return { field: fieldProps.value, value: value.value, @@ -177,22 +187,11 @@ export const Field = defineComponent({ setTouched, setErrors, }; - }); - - if ('modelValue' in props) { - const modelValue = toRef(props, 'modelValue'); - watch(modelValue, newModelValue => { - if (newModelValue !== applyModifiers(value.value, props.modelModifiers)) { - value.value = newModelValue; - validateField(); - } - }); } return () => { const tag = resolveDynamicComponent(resolveTag(props, ctx)) as string; - - const children = normalizeChildren(ctx, slotProps.value); + const children = normalizeChildren(tag, ctx, slotProps); if (tag) { return h( diff --git a/packages/vee-validate/src/Form.ts b/packages/vee-validate/src/Form.ts index f5cec277e..77e1e9a79 100644 --- a/packages/vee-validate/src/Form.ts +++ b/packages/vee-validate/src/Form.ts @@ -85,7 +85,7 @@ export const Form = defineComponent({ return handleSubmit(onSuccess as SubmissionHandler>)(evt as Event); } - const slotProps = computed(() => { + function slotProps() { return { meta: meta.value, errors: errors.value, @@ -105,7 +105,7 @@ export const Form = defineComponent({ setTouched, resetForm, }; - }); + } return function renderForm(this: any) { // FIXME: Hacky but cute way to expose some stuff to the rendered instance @@ -123,7 +123,9 @@ export const Form = defineComponent({ this.validateField = validateField; } - const children = normalizeChildren(ctx, slotProps.value); + // avoid resolving the form component as itself + const tag = props.as === 'form' ? props.as : (resolveDynamicComponent(props.as) as string); + const children = normalizeChildren(tag, ctx, slotProps); if (!props.as) { return children; @@ -139,8 +141,7 @@ export const Form = defineComponent({ : {}; return h( - // avoid resolving the form component as itself - props.as === 'form' ? props.as : (resolveDynamicComponent(props.as) as string), + tag, { ...formAttrs, ...ctx.attrs, diff --git a/packages/vee-validate/src/utils/vnode.ts b/packages/vee-validate/src/utils/vnode.ts index 7b1ee0ea6..679b64cb9 100644 --- a/packages/vee-validate/src/utils/vnode.ts +++ b/packages/vee-validate/src/utils/vnode.ts @@ -3,12 +3,22 @@ import { SetupContext } from 'vue'; type HTMLElementWithValueBinding = HTMLElement & { _value: unknown }; // eslint-disable-next-line @typescript-eslint/no-explicit-any -export const normalizeChildren = (context: SetupContext, slotProps: Record) => { +export const normalizeChildren = ( + tag: string | Record | undefined, + context: SetupContext, + slotProps: () => Record +) => { if (!context.slots.default) { return context.slots.default; } - return context.slots.default(slotProps); + if (typeof tag === 'string' || !tag) { + return context.slots.default(slotProps()); + } + + return { + default: () => context.slots.default?.(slotProps()), + }; }; /**