Reputation: 2137
I’ve got a simple REPL example for a simple list-detail editor. It’s made up of three components:
Annotation
is the detailAnnotations
loops through the data and creates Annotation
instancesApp
is the top-level that creates the Annotations
I’ve figured out how to wire up a custom Svelte store to manage the Array
of instance data for the Annotations
. I can use this by importing the store directly into the Annotations
component and calling it without any props from the top-level App
component. However, I’d like to be able to pass the store in as a property on the Annotations
component from the App
parent, i.e. <Annotations items={store}/>
, not <Annotations/>
.
Is this possible? I would think that injecting the store from a parent component would be more flexible/testable than importing it from the component itself. Have I done too much dependency injection with Spring in Java and I’m thinking about the Svelte model incorrectly?
Upvotes: 5
Views: 6470
Reputation: 25001
Yes, absolutely. This can easily be demonstrated with a few modifications of your REPL.
In App.svelte
, as you said:
<Annotations items={annotations} />
In Annotations.svelte
, add the items
prop, and replace references of annotations
with it:
<script>
export let items
...
items.addStuff(...);
</script>
{#each $items as annotation}
...
{/each}
There's no catch at all... You can pass whatever type of value you want as component props, there's no marshalling or whatever.
You can even pass other components, if you're so inclined!
<script>
export let Cmp // yes, can change at runtime, reactive!
</script>
<svelte:component this={Cmp} />
<!-- or -->
{#if Cmp}
<Cmp />
{/if}
But I digress, sorry! So, it is possible. Now, is it a good idea? I think your experience with Spring & dependency injection totally transfers here. It will indeed make your component more flexible and more testable, at the cost of more boilerplate. There are some situations where this trade off is good, and some where it is bad.
Personally, I'm of the opinion that this pattern often does more good than harm.
One thing to consider is that when you import the store directly into the component, you make it kind of a singleton, data-wise. Even if you can have multiple instances of the component rendered on the screen, they will all necessarily use exactly the same data. On the other hand, when the store is passed by prop, you can reuse the same component with different stores (obviously). You can even swap the store used by a component at runtime, without recreating the component! So, like you said, more flexible.
One issue that arises from this practice is that you'll have to decide where you will import the stores. What components will be responsible for owning the stores, as opposed to just consume them? How many levels deep are you OK with passing a store down manually by props? In React parlance, we'd probably be speaking "dumb components" vs "containers". There's a real question (and debate) here, that is not specific to Svelte, and that gets different answers depending on who you ask, or the kind of project.
One other option to consider is that you can put stores into context, so you won't have to pass them down through the whole component hierarchy. On the other hand, the data flow becomes harder to track, even though good naming and consistent patterns can really mitigate this problem.
Yet another technique you can consider is to have stores of stores...
To sum it up, you don't have a lot of limitations on what Svelte let you do, appart from the explicitly stated contracts of its primitives (props, stores, context...). This lets you imagine or reuse techniques from other frameworks, with largely similar outcomes in term of costs and benefits.
Upvotes: 18