Svelte中如何柯里化组件参数创建组件工厂(Component Factories)
Svelte 组件参数柯里化实现
通过高阶组件包装的思路就能实现组件props的柯里化,不需要引入第三方依赖,以下是不同Svelte版本下可直接运行的代码:
Svelte 3/4 兼容实现
针对Greet组件的专用工厂
新建greetFactory.ts,写入以下代码即可匹配示例用法:
import Greet from './Greet.svelte'; import type { SvelteComponent, ComponentType } from 'svelte'; export function greetFactory(name: string): ComponentType<SvelteComponent<{ greeting: string }>> { return class CurriedGreet extends SvelteComponent<{ greeting: string }> { private inner: Greet; constructor(options: ConstructorParameters<typeof SvelteComponent>[0]) { super(options); // 合并预绑定的固定参数与外部传入的剩余参数,实例化原组件 this.inner = new Greet({ target: this, props: { ...options.props, name } }); } // 代理响应式更新,保证外部传参变化时组件正常刷新 $set(props: Partial<{ greeting: string }>) { this.inner.$set(props); } // 代理销毁逻辑,避免内存泄漏 $destroy() { this.inner.$destroy(); super.$destroy(); } } }
该写法不需要修改原有Greet.svelte的代码,组件渲染、响应式更新、销毁逻辑都能正常运行。
通用Props柯里化工具
如果需要对多个组件做参数柯里化,可以抽成通用工具函数,避免重复编写包装逻辑:
import type { SvelteComponent, ComponentType, ComponentProps } from 'svelte'; export function curryComponentProps< Comp extends SvelteComponent<any>, FixedKeys extends keyof ComponentProps<Comp> >( Component: ComponentType<Comp>, fixedProps: Pick<ComponentProps<Comp>, FixedKeys> ): ComponentType<SvelteComponent<Omit<ComponentProps<Comp>, FixedKeys>>> { return class CurriedComponent extends SvelteComponent<Omit<ComponentProps<Comp>, FixedKeys>> { private innerInstance: Comp; constructor(options: ConstructorParameters<typeof SvelteComponent>[0]) { super(options); this.innerInstance = new Component({ target: this, props: { ...fixedProps, ...options.props } }); } $set(props: Partial<Omit<ComponentProps<Comp>, FixedKeys>>) { this.innerInstance.$set(props); } $destroy() { this.innerInstance.$destroy(); super.$destroy(); } } }
使用示例:
<script lang="ts"> import Greet from './Greet.svelte'; import { curryComponentProps } from './curryComponentProps'; // 预绑定name参数 const GreetMike = curryComponentProps(Greet, { name: 'Mike' }); </script> <GreetMike greeting="Hello" />
Svelte 5 极简实现
Svelte 5中组件本身是普通函数,柯里化逻辑和普通函数柯里化完全一致,不需要写类包装,代码非常简洁:
import Greet from './Greet.svelte'; import type { Component } from 'svelte'; export function greetFactory(name: string): Component<{ greeting: string }> { return (props) => Greet({ ...props, name }); }
对应的通用柯里化工具也更简单:
import type { Component, ComponentProps } from 'svelte'; export function curryComponentProps< Comp extends Component<any>, FixedKeys extends keyof ComponentProps<Comp> >( Component: Comp, fixedProps: Pick<ComponentProps<Comp>, FixedKeys> ): Component<Omit<ComponentProps<Comp>, FixedKeys>> { return (props) => Component({ ...fixedProps, ...props }); }
注:如果原组件需要透传事件、插槽,Svelte 3/4的类实现需要额外补充事件监听、插槽挂载逻辑,无事件/插槽的简单展示组件可直接使用上述代码。
内容的提问来源于stack exchange,提问作者a pfp with melon
相关产品推荐
相关产品推荐

