simplify implementation - create action first, then only create update/destroy effects if necessary

pull/15958/head
Rich Harris 4 months ago
parent 5a18de243b
commit 7d6fea7b14

@ -1,9 +1,8 @@
/** /** @import { FromAction } from './public.js' */
* @import { FromAction } from "./public.js"; import { noop, render_effect } from 'svelte/internal/client';
* @import { ActionReturn } from "svelte/action";
*/
import { render_effect } from 'svelte/internal/client';
import { ATTACHMENT_KEY } from '../constants.js'; import { ATTACHMENT_KEY } from '../constants.js';
import { untrack } from 'svelte';
import { teardown } from '../internal/client/reactivity/effects.js';
/** /**
* Creates an object key that will be recognised as an attachment when the object is spread onto an element, * Creates an object key that will be recognised as an attachment when the object is spread onto an element,
@ -36,36 +35,21 @@ export function createAttachmentKey() {
* attachments on Components but you have library provided actions. * attachments on Components but you have library provided actions.
* @type {FromAction} * @type {FromAction}
*/ */
export function fromAction(action, args) { export function fromAction(action, /** @type {() => any} */ get_arg = noop) {
return (element) => { return (element) => {
/** const { update, destroy } = untrack(() => action(element, get_arg()) ?? {});
* @typedef {typeof args} Args;
*/
/** if (update) {
* @type {ReturnType<NonNullable<Args>> | undefined} var ran = false;
*/
let actual_args;
/**
* @type {ActionReturn['update']}
*/
let update;
/**
* @type {ActionReturn['destroy']}
*/
let destroy;
render_effect(() => { render_effect(() => {
actual_args = args?.(); const arg = get_arg();
update?.(/** @type {any} */ (actual_args)); if (ran) update(arg);
}); });
ran = true;
}
render_effect(() => { if (destroy) {
return () => { teardown(destroy);
destroy?.(); }
};
});
({ update, destroy } = /** @type {ActionReturn} */ (
action(element, /** @type {any} */ (actual_args))
));
}; };
} }

Loading…
Cancel
Save