Skip to content
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

Slider does not react immediately to store values updated in onMount #15

Closed
mechbear14 opened this issue Aug 27, 2024 · 4 comments
Closed
Assignees
Labels
bug Something isn't working

Comments

@mechbear14
Copy link

Svelte Tweakpane UI version: 1.3.0
Svelte version: 4.2.19

I'm trying to update a store value inside onMount. The value is then used and controlled by Svelte Tweakpane UI. However, the update in the store is not picked up by Svelte Tweakpane UI.

Example

<script lang="ts">
	import { writable } from 'svelte/store';
	import { Slider } from 'svelte-tweakpane-ui';
	import { onMount } from 'svelte';

	const bear = writable({ name: 'Cleeve', apples: 100 });

	onMount(() => {
		const { name } = $bear;
		bear.set({ name, apples: 60 });
	});
</script>

<p>Native input</p>
<input type="range" bind:value={$bear.apples} min={0} max={100} step={1} />
{$bear.apples}
<p>Svelte Tweakpane UI</p>
<Slider bind:value={$bear.apples} min={0} max={100} step={1} />

image

I expect the value in Tweakpane to be 60 as the native <input> element.

However, when I put these into a setInterval, it works correctly.

<script lang="ts">
	import { writable } from 'svelte/store';
	import { Slider } from 'svelte-tweakpane-ui';
	import { onMount } from 'svelte';

	const bear = writable({ name: 'Cleeve', apples: 100 });

	onMount(() => {
		setInterval(() => {
			const { name, apples } = $bear;
			bear.set({ name, apples: apples - 1 });
		}, 2000);
	});
</script>

<p>Native input</p>
<input type="range" bind:value={$bear.apples} min={0} max={100} step={1} />
{$bear.apples}
<p>Svelte Tweakpane UI</p>
<Slider bind:value={$bear.apples} min={0} max={100} step={1} />

image

It looks like a little delay is needed to make this work. Could you have a look at this and see if there's a race condition or anything?

PS: I need to use a store because there are other listeners in the actual project. Also, I need to set the value in onMount because it comes from the URL query string.

Thanks

@kitschpatrol
Copy link
Owner

kitschpatrol commented Aug 28, 2024

Hi, thanks for opening this.

I think this is related to some variation of this issue... the <Slider> component implementation uses a reactive statement to detect changes, and in your example this has already fired on the 100 value in the same frame, and subsequent updates are ignored. Internally, I'm seeing the 60 value making it into the component, but failing to trigger the reactive statement.

This is actually kind of tricky to fix without rearchitecting Svelte Tweakpane UI to use stores instead of reactive statements in a number of places, but I'll look into it.

In the meantime, a slightly cleaner / Svelter workaround for your specific case is to wait for a tick() before updating the apple count in in onMount:

<script lang="ts">
	import { writable } from 'svelte/store';
	import { Slider } from 'svelte-tweakpane-ui';
	import { onMount, tick } from 'svelte';

	const bear = writable({ name: 'Cleeve', apples: 100 });

	onMount(() => {
		await tick();
		$bear.apples = 60;
	});
</script>

<p>Native input</p>
<input type="range" bind:value={$bear.apples} min={0} max={100} step={1} />
{$bear.apples}
<p>Svelte Tweakpane UI</p>
<Slider bind:value={$bear.apples} min={0} max={100} step={1} />

Not great, but should work for now.

Also, depending on how you're getting values from the URL query parameters, waiting for onMount() might not be necessary. You could even bind the Svelte Tweakpane UI slider directly to a store proxying the URL query parameters if that's what you're after... take a look at something like sveltekit-search-params if you're working with SvelteKit.

@kitschpatrol kitschpatrol self-assigned this Aug 28, 2024
@kitschpatrol kitschpatrol added the bug Something isn't working label Aug 28, 2024
@kitschpatrol kitschpatrol added this to the Svelte 5 Support milestone Sep 11, 2024
@kitschpatrol
Copy link
Owner

kitschpatrol commented Sep 11, 2024

Hi again. This is not forgotten, but since this behavior is coming from Svelte itself I just don't see a simple fix for it in the current Svelte 4-based implementation of Svelte Tweakpane UI.

This has been identified as something that will be fixed in Svelte 5, so a future Svelte 5-based implementation of Svelte Tweakpane UI should (eventually) address this issue.

In the meantime, please use the await tick() workaround demonstrated above.

@kitschpatrol kitschpatrol modified the milestones: Svelte 5 Rewrite, 2.0 Sep 11, 2024
@mechbear14
Copy link
Author

Hi. Thanks for your response. Yes. I have to say await tick() is awkward, but probably it's because (I guess) it wants to collect all component states before a render, so as to avoid repeated renders. That makes sense, so I guess this is what I have to do for now.

kitschpatrol added a commit that referenced this issue Sep 15, 2024
@kitschpatrol kitschpatrol removed this from the 2.0 milestone Oct 21, 2024
@kitschpatrol
Copy link
Owner

kitschpatrol commented Oct 22, 2024

Hi, I just finished up adding support for Svelte 5 to Svelte Tweakpane UI — and it does seem like this particular issue is resolved in projects targeting the Svelte 5 compiler. Projects targeting Svelte 4 will need to continue to use the tick() workaround.

Closing this since it's now working in Svelte 5, and I unfortunately don't see a path to a fix in Svelte 4.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants