[🐞] If Signal is used by useTask$ it doesn't re-render should it work that way?
Which component is affected?
Qwik Runtime
Describe the bug
On button clicking I set value of Signal to true, If Signal is true, I want to hide button until task is completed, it works with useVisualTask$ but doesn't work with useTask$, am I doing something wrong?
check out reproduction url https://stackblitz.com/edit/qwik-starter-sbzklc?file=src%2Froutes%2Findex.tsx,package.json
export const ServerTask = component$(() => {
const page = useSignal(1);
const loading = useSignal(false);
useTask$(async ({ track }) => {
track(page);
if (loading.value) {
await new Promise((r) => setTimeout(r, 1000));
loading.value = false;
}
});
const increase = $(async () => {
page.value++;
loading.value = true;
});
return (
<>
{page.value} - {loading.value ? 'loading...' : 'loaded!'}
<br />
{!loading.value && <input type="submit" onClick$={increase} />}
</>
);
});
Reproduction
https://stackblitz.com/edit/qwik-starter-sbzklc?file=src%2Froutes%2Findex.tsx,package.json
Steps to reproduce
No response
System Info
npx envinfo --system --npmPackages '{vite,undici,@builder.io/*}' --binaries --browsers
Additional Information
No response
Looks like there's an issue with the useVisibleTask example too. The page count doesn't increase past 2.
Looks like there's an issue with the useVisibleTask example too. The page count doesn't increase past 2.
I didn't saw it at first, but you are right, maybe that's also a bug? I have edited the code
{!loading.value && (
<input
type="submit"
value="Button that works only one time with useVisibleTask$, but always with useTask$, why?"
onClick$={increase}
/>
)}
<input
type="submit"
onClick$={increase}
style={`${loading.value && 'background:red;'}`}
/>
I wanted to take another look and try a few things. It seems the use of await inside useTask is causing the bug. I created an example repo with 3 example components. The only difference between each component is the code within the useTask.
https://stackblitz.com/github/tuurbo/qwik-task-bug?file=src%2Froutes%2Findex.tsx
I think I encounter a similar bug in the QwikCityProvider in line 504. The update call routeLocation.isNavigating = false; is triggered, but useTask$ is not always notified. It works with useVisibleTask$ for me.
Let's wait until v2 alpha is out to check if the bug still exists there. In the mean time it would be very helpful to create the repro in https://qwik.dev/playground so that it's easy to test with the alpha
Here is a slimmed down example
https://qwik.dev/playground/#f=7ZdNb9NAEIb%2Fymg5JLSJkyJFRUkDEtATEpUoiCNyHCexcGzLdmhQlP%2FOO7OzaycupVckfGjj9e7szOx8PNsOmtfXk8eiZuB7rvySujagJ4PJS0mqd2X%2BwA1PZ5vOscq7eWYAKjEIUcy9XtaL%2FJ0fxocpXQ30NUWe4zSntArTKrajR%2FvPrUAmIUJ%2BYhVXa51iXeT3TDJOOBTaObUVIqtMwJteXs4wwpnQaBrXXGeYfGSdV2aRg0zCrCNHJ2C2%2FuqIRBV9H6LWszxbV9vaaFy1GmC%2FX8r3pnn3ywFdjcfjlxDrhXsSUpkHpZtjS7iMqPGN2XY9UbKivj9vm1f8jC7koQ93t%2FefvtC3u88fyQ5djHSKbdpqWF%2B0Eo945%2FXl7NxGRGeiWeb9uVBghpcYcNM9OTX5%2FugW%2Fis7xkWCOukPWQsyVm40Rbi0Bzwp9jP6vkJ5Hj7EyXpT85mnyxnJUIUegRi9xiTTpOztvhComgI6uIda0iagExjjxhLxmy2SI0ErvhnpgHBFRXVuY1T4RRDaAlhALgIrMCAgJtqEGb7a5M3yHq%2Fs%2FYqrHi13wuir8AewCc06gvMCX0CY%2F%2F9q8Ra4lWTDRQ7Nt7BwzINPmPy14h17EgE9GFChuflYxPEwqkC%2FBRgKfBDt0qJM6oCU00Yo7UpsUY6FzGGgE78eKyGCMV78CjEb9O%2B8fL5Rr8QAcHMB2EENSWO2B3%2BHy6S0wIYrUJ7uttmM1mHhTAYFrLOhoJZdNcTNp6xnCIIS1Q%2BCiz0B7JIlvYiiyDlOl7ccJNcvW9IOTc4dTzTXWb646ERXS96SwfEampLJctNZaqPMvyPN0ZTnxg6b1ri7PcxP5XN%2BuMffhQ6nydZJaC60Ptns4ypsUwAk%2B9ri9XJ2KjXalVUOjxoB47g0rvKrSkUYJTXO7twp42ACl%2Fg%2BIZuBVPla1OzZ%2BIk0HRvHuZtwN5iaDvsfi%2F5JLPoN
this works as expected because of how promises work
here is the correct way to handle true/false loading
onClick$={[
$(async () => {
await setLoading(true);
}),
$(async () => {
await increase();
await apiCall();
}),
$(async () => {
await setLoading(false);
})
]}
(the added benefit is that if the page changes the rest of the handlers don't get invoked)
https://qwik.dev/playground/#f=7VhRb9NADP4rVnhIxtq0G5rQ2hUkYE9ITGIgHhBCaZpuEW0SJS0bmvrf%2BWxf7i5LNybxhEQe1sR39tk%2B33ef5xXN8YvT031VM7B3rrwJrg3IiBW6HqkrazBv3tTlDd99ZnbQ22H5Dp5Yi5pY4Qoz50p0dGDHlHjoIL9qslmXH9ac0NHAfK4AB9j0CS2TVZOpdKc%2FrQYOHArpJ7QY1M0UzaRdMy%2F4XAKPZ%2BQ7S%2BpMzIseHk5Fwu8xUGRrJT5hCXk4HHh6A0%2BDg%2BQj52LNNgxoTLFkZRvOvITFpOh5YiZgtnljFzomAddvE1wqbE8B3I%2Bnd9FGUS3DjiRE9YCOxuPxAaxa27j9LekyVu8MkdpZ85hEKvRyKMJ7SZI5nSxxZsxMc8bcWDvkXCHKlxTZ0lQ0MOqj5%2FLQu4vzyw%2Bf6MvFx%2FekouejB9yZZ2BPoBxVHnp%2BaKpMOiNJxj7lZAmutl%2FX7W4k5fmgjQWOCdRNwfZj4SAu90SBH%2BtfzAyln3f5ecwR%2FHBi2xzri0n1A3CHlsIQ7qBKFlqwJ9XtlL4vca8Nb7L86nrDNbxaTElEDS5XnNqXmBQ4rDu%2FrYSNTsDWmHxoi0LgnCBnZ9pKvFoDSnJwmLOREQgha2hT6qkV4id4osw1pvZENSDPYH%2FpdVJgVKGuKEPWDH9lTUiLrTQ3y%2BSHbD6lSGRskZcbpz9GvAZPzYvhvITna0Q4ZuEjIX9ueMVQ6iNEAA1YgT1Z2CfmePBvDvIJYpVuV1Wdb2IyBHeEO9FQ3bSEIhNY0DqrD02Y4P5H8goz1yA%2BZf30oI4lADQcFVgiUHWVcTz4O1zktTJd9I7larsupnSVVG3IoE9XxVA4qmoN0TLWmymKoMZdAcPVLaHg8wU9S9O0TZxR9xIkfauC%2FJ2DgF3HczPLgqWZ2GLjawqwvQFNKCjKoKeqVWa%2FgVhgM7NAxYEnb9uuWdc%2BH5H2sU3k3VdPSnuh1z09dOCLSc6ge3YH7RX3dIvtLaZg1R%2FvYNnfLbUXUXyT3uc3P2OmUe9aTbd1U6JIAmmSsjroOlRWSZpvUI7393kcn2CXLRmQldG1cIvs1nRbTwZhXC20%2FxXpnw%2FHtv5T5H%2BSIv8G
the reason why the example before only worked with .then() is that it was a side-effect
apiCall().then(() => {
setLoading(false);
});
the signal was fired async after apiCall finishes the task