chi*_*org 10 dependency-injection svelte
我有几个服务类(其中一些“获取这些参数的数据”和一些“计算这些参数的内容”方法)我想注入到我的 Svelte 组件层次结构中的几个组件中。目前,我看到了以下选项,但没有一个非常有吸引力:
在 Vue 中,我会编写一个插件,添加所有 Vue 组件中可用的属性。做到这一点的 Svelte 方法是什么?
hel*_*joe 11
我遇到了同样的问题。当不需要设置时,很容易执行 Rich Harris 的建议并从单独的 JS 文件导出服务,但我遇到了一个问题:延迟加载。与您的问题不同,但相似之处在于服务无法立即可用。
我想通过动态导入来延迟加载 Firebase,因为它相当重。这意味着在承诺解决之前,服务无法访问数据库import()
,因此导出它们并不那么简单。我找到了几个解决方案:
您提到商店似乎有点矫枉过正,因为服务是静态的。您可以为此使用上下文!有一个问题:setContext
需要在初始化期间同步调用(即不在 中onMount
)。如果您的配置同步发生,您应该能够避免额外的层,但这就是我所做的:
在应用程序顶部创建一个额外的组件来实例化服务并将它们作为 props 传递到 root 中App
,您可以在其中将它们传递到setContext
. 您需要上面的额外组件App
来确保服务存在,然后再将它们设置到上下文中。使用 Svelte 的{#await promise}
语法,您可以确保在传递 prop 之前进行初始化:
初始化服务.svelte
<script>
import config from './config';
import createServices from './services';
import App from './App.svelte';
const services = createServices(config);
</script>
{#await promise then services}
<App {services} />
{/await}
Run Code Online (Sandbox Code Playgroud)
应用程序.svelte
<script>
import Child from './Child.svelte';
export let services;
setContext('services', services);
</script>
<Child /> <-- contains Grandchild.svelte
Run Code Online (Sandbox Code Playgroud)
孙子.苗条
<script>
const services = getContext('services');
const promise = services.getData();
</script>
{#await promise then data}
<div>Hello {data.username}!</div>
{/await}
Run Code Online (Sandbox Code Playgroud)
皱纹#2:我用 编写了一些测试@testing-library/svelte
,他们现在抱怨来自 的服务getContext
,因为没有家长打电话setContext
。
一种解决方案是创建一个TestContextWrapper.svelte
,它可以工作,但会增加一些额外的复杂性(不是很多,但也不是没有)。这是一个例子:https://svelte-recipes.netlify.app/testing/#testing-the-context-api
所以...我决定用商店替换上下文,结果效果很好。反应式存储对于测试来说是一个好处,因为您可以使用模拟服务实例化存储,并在需要时动态更新它。
我仍然将服务作为应用程序顶部的支柱传递,以避免空检查,但除此之外,这还清理了很多东西。 服务商店.js
import { writable } from 'svelte/store';
export const serviceStore = writable(null);
Run Code Online (Sandbox Code Playgroud)
InitServices.svelte (同上)
应用程序.svelte
<script>
import serviceStore from './services-store';
import Child from './Child.svelte';
export let services;
serviceStore.set(services);
</script>
<Child /> <-- contains Grandchild.svelte
Run Code Online (Sandbox Code Playgroud)
孙子.苗条
<script>
import serviceStore from './services-store';
const promise = $serviceStore.getData();
</script>
{#await promise then data}
<div>Hello {data.username}!</div>
{:catch err}
<p>Error! {err.message}</p>
{/await}
Run Code Online (Sandbox Code Playgroud)
孙子.test.js
import serviceStore from './services-store';
let mockService;
beforeEach(async () => {
mockService = { getData: jest.fn().mockResolvedValue('helloitsjoe') };
serviceStore.set(mockService);
});
...
it('shows username', async () => {
render(Grandchild);
const name = await findByText('helloitsjoe');
expect(name).toBeTruthy();
});
it('shows error', async () => {
// Override mock service
mockService.getData.mockRejectedValue(new Error('oh no!'));
render(Grandchild);
const message = await findByText('oh no!');
expect(message).toBeTruthy();
});
Run Code Online (Sandbox Code Playgroud)