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;
*/ render_effect(() => {
let actual_args; const arg = get_arg();
/** if (ran) update(arg);
* @type {ActionReturn['update']} });
*/ ran = true;
let update; }
/**
* @type {ActionReturn['destroy']}
*/
let destroy;
render_effect(() => {
actual_args = args?.();
update?.(/** @type {any} */ (actual_args));
});
render_effect(() => { if (destroy) {
return () => { teardown(destroy);
destroy?.(); }
};
});
({ update, destroy } = /** @type {ActionReturn} */ (
action(element, /** @type {any} */ (actual_args))
));
}; };
} }

Loading…
Cancel
Save