qwik: [🐞] Qwik doesnt check `if-statements` before running child useComputed$ or useTask$
Which component is affected?
Qwik Runtime
Describe the bug
The following code causes Qwik to crash when the button is clicked. Conditionals aren’t checked before child component tasks are run when using Signals.
import { component$, useSignal, useTask$ } from "@builder.io/qwik";
// A useTask$ in a child components circumvents the parent components conditional checks
const Child = component$((props: { val: string }) => {
useTask$(({ track }) => {
track(() => props.val)
});
return <>{props.val}</>;
});
export default component$(() => {
const sig = useSignal<{ data: string } | undefined>({ data: '' });
return (
<>
<button onClick$={() => (sig.value = sig.value ? undefined : { data: '' })}>Toggle</button>
{/* ERROR: cannot read data of undefined */}
{sig.value && <Child val={sig.value.data} />}
</>
);
});
Reproduction
https://github.com/DustinJSilk/qwik-issue-rendering/blob/main/src/routes/index.tsx
Steps to reproduce
Run the app Click the button
System Info
System:
OS: macOS 12.0.1
CPU: (12) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
Memory: 116.35 MB / 16.00 GB
Shell: 5.8 - /bin/zsh
Binaries:
Node: 18.12.1 - ~/.nvm/versions/node/v18.12.1/bin/node
Yarn: 1.22.18 - /usr/local/bin/yarn
npm: 7.13.0 - /usr/local/bin/npm
Browsers:
Chrome: 113.0.5672.126
Firefox: 113.0.1
Safari: 15.1
npmPackages:
@builder.io/qwik: ^1.1.4 => 1.1.4
@builder.io/qwik-city: ^1.1.4 => 1.1.4
undici: 5.22.1 => 5.22.1
vite: 4.3.5 => 4.3.5
Additional Information
No response
About this issue
- Original URL
- State: open
- Created a year ago
- Reactions: 2
- Comments: 23 (16 by maintainers)
Commits related to this issue
- test(v2): add test for #4332 — committed to Varixo/qwik by Varixo 4 months ago
- test(v2): test for issue #4332 (#5988) test(v2): add test for #4332 — committed to QwikDev/qwik by Varixo 4 months ago
Sorry for the cryptic example!
What I was trying to show is that based on the contract of the
Child
component, as long as you don’t pass “bananas”, everything is fine. And naively, it does seem like we’re following that contract in that example.Here’s another example to show the sorts of things a real world app might try to do.
I would describe the problem simply that type narrowing does not work on signals.
No matter what we write in the render logic, at runtime, the signal is not type narrowed, because it gets flushed through before the narrowing logic can run.
This can be a source of bugs that Typescript cannot detect.
Thanks @mhevery and @wmertens i appreciate you guys taking the time to think about this one!
I wish this bug had more attention!
Here’s a playground example just to show how bananas this behavior is 🙈
https://qwik.builder.io/playground/#v=1.2.13&f=7Va7CoNAEOzzFRubUwiBFIEgnqn8iJQaErTR4AMC4r9ndvfUK1LYBqIgKnd7t3uzM%2BOB5nxZ0vFBc1jVV16F17YgSTNX4rRewGTk3hke8ewJpjQULzHXZhHl8N6%2Fl4oR4esokusQKZOOEiuSAdWTNJL%2BJGstmSKvcXdGT5qvvmzB2awRWds2bWhuzUAdBBIbrXFOZQ66fcHVQCjd7L3RFSY8p2jntQK7IhVBcFgwestPgXom9Ma27tKCua2vVQ8NFvcg49CSlKc0Y3mnwG0yoJ7dAewVpwVwnFKeh6GV%2BKECPBNLeDvqDhkfMkK%2Fv5WNriotMSV6lH4AlyjCcGGAq%2BhPBD9KBB8