Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
fix: minor perf enhancement by lazy evaulation of slot props
  • Loading branch information
logaretm committed Apr 18, 2021
1 parent eac4dfe commit a306b1b
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 26 deletions.
16 changes: 10 additions & 6 deletions packages/vee-validate/src/ErrorMessage.ts
Expand Up @@ -19,31 +19,35 @@ 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,
};

// 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 <span> with the message in it's contents
if (!children?.length) {
if ((Array.isArray(children) || !children) && !children?.length) {
return h(tag || 'span', attrs, message.value);
}

Expand Down
25 changes: 12 additions & 13 deletions packages/vee-validate/src/Field.ts
Expand Up @@ -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,
Expand All @@ -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(
Expand Down
11 changes: 6 additions & 5 deletions packages/vee-validate/src/Form.ts
Expand Up @@ -85,7 +85,7 @@ export const Form = defineComponent({
return handleSubmit(onSuccess as SubmissionHandler<Record<string, unknown>>)(evt as Event);
}

const slotProps = computed(() => {
function slotProps() {
return {
meta: meta.value,
errors: errors.value,
Expand All @@ -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
Expand All @@ -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;
Expand All @@ -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,
Expand Down
14 changes: 12 additions & 2 deletions packages/vee-validate/src/utils/vnode.ts
Expand Up @@ -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<any>, slotProps: Record<string, unknown>) => {
export const normalizeChildren = (
tag: string | Record<string, unknown> | undefined,
context: SetupContext<any>,
slotProps: () => Record<string, unknown>
) => {
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()),
};
};

/**
Expand Down

0 comments on commit a306b1b

Please sign in to comment.