-
-
Notifications
You must be signed in to change notification settings - Fork 4.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Svelte 5: can't link reactivity from $props()
#14536
Comments
One workaround (intended pattern?) we were discussing over in discord was using // +page.svelte
let { data } = $props();
// deeply reactive state
let cards = $state(data .cards);
// updated when the load function re-runs
$effect(() => {
cards = data.cards;
}); Which makes a certain kind of sense, based on this graf:
We're syncing local app state with new data from the network, so maybe this isn't a bug, but the intended behavior. If so, I think this kind of example should be discussed in the docs, because it feels like a gotcha. I'd be happy to write up something. |
IMHO this is a huge regression and breaks every page on our large svelte 4 application as they all use (what we were trained to do) the data directly in our bindings with full reactivity by default. export let data
bind:value={data.db_query_result.column_name} this now has to have onerous boiler plate additional refactor everywhere as follows let { data } = $props();
let data_db_query_detail = $state(data.db_query_result);
bind:value={data_db_query_detail.column_name} The migrate script just slaps a $bindable() on the data prop which does nothing in regards to reactivity
|
I'm having the same problem and I'm also unsure how to best handle this. A lot of pages in my SvelteKit app broke because I used something like this to unpack the <script>
export let data
$: ({ order } = data)
</script>
<input bind:value={order.email} /> I want to be able to
I tried a few different things. This one does not work because I can't update the state locally: const { data } = $props()
const { order } = $derived(data) This one does not work because the state does not receive prop updates: const { data } = $props()
const { order } = $state(data) This one does not work because the Svelte compiler gives an error " const { data } = $props()
const { order } = $derived($state(data)) But this one does work: function withWrites<T>(initialState: T): T {
const state = $state(initialState)
return state
}
const { data } = $props()
const { order } = $derived(withWrites(data)) This feels doubly weird, because I can't use state directly … but I can wrap it in a function and then it's fine? While this does work, this almost feels like a coincidence. But I think I'll still go with this for now, as it at least does what I want, is pretty clean and I don't need the additional |
You can do it with an We have this issue anywhere you want to set the value of some The case of |
$props()
<script>
let { data } = $props();
// Is editable, but resets when the `data.cards` signal is updated
let cards = stateLink(() => data.cards);
function stateLink(getValue) {
let wasLocal = false;
let localState = $state(undefined);
// Choose `localState` as the latest value if the mutation was local
// Otherwise, choose the linked `getValue()` because the change was a reaction
const linkedDerived = $derived.by(() => {
const linkedValue = getValue();
localState; // watch
if (wasLocal) {
wasLocal = false;
return localState;
}
return linkedValue;
});
return {
get current() {
return linkedDerived;
},
set current(v) {
wasLocal = true;
localState = v;
},
};
}
</script> See https://svelte.dev/playground/23189440a69f4b0ebccdc0e08964ec19 |
Interested in this solution. The Svelte4 pattern of page.data being reactive makes a lot of sense. Would like to see that pattern preserved in Svelte5. |
solutions currently exist in sveltejs/kit#12999 and sveltejs/kit#13000 |
I just stumbled upon this issue too and I am surprised that this (#15107 (comment)) seems to be the actual right way to do it? This feels so unlike svelte tbh and completely kills the DX, which is one of svelte's main selling points and why I love using svelteKit so far. I just started working on my first project with svelteKit, so I'm not that experienced with svelteKit, which is why it took me longer than I want to admit to find the issue to why my message in Also for a beginner it's already difficult enough to figure out when to use |
We plan to add it to the docs soon, I also think we should probably abstract this concept in a |
Possible with something like export class Linked<T> {
value: T = $state() as T;
constructor(get: () => T) {
this.value = get();
$effect(() => {
this.value = get();
});
}
} but it's a bit painful needing to access the nested let reactive = new Linked(() => someProp);
console.log(reactive.value); // would be nice if this was just 'console.log(reactive)' As far as I know there's no way around this in userland? |
See the linked comment...the much better way is creating state in derived.by |
Sure, I'm not too bothered about the internals of what a userland version |
Yeah if we do add |
Addressed in #15570 |
Describe the bug
This is most apparent when implementing pagination, but when trying to use deeply nested reactivity with page data objects in a svelte kit route (e.g.
$state(data.foo)
), it breaks the connection to$props()
.Accessing directly with dot notation stays in sync with
$props()
, but does not have reactive state (as expected). The only way to stay in sync with$props()
and get reactive state is to use component context to create local reactive state.Reproduction
Here's a stack blitz with sveltekit repro. I can only get the expected reactivity by creating
$state()
in a component based on local primitive values.https://stackblitz.com/edit/svelte-rune-page-data-bug?file=src%2Froutes%2F%2Bpage.server.ts,src%2Froutes%2F%2Bpage.svelte,src%2Flib%2Fbullet.svelte
And here's a svelte repro that shows similar behavior, but since the parent
App.svelte
component can create$state()
and pass it into the component, the issue is not as apparent.https://svelte.dev/playground/6fe00097a3104b11b9922df28b668598?version=5.1.3
Logs
No response
System Info
Severity
serious, but I can work around it
Additional Information
No response
The text was updated successfully, but these errors were encountered: