sync$()
Synchronous Events (BETA)
Qwik processes events asynchronously. This means that some APIs such as event.preventDefault()
and event.stopPropagation()
do not work as expected. To work around this limitation, Qwik provides a sync$()
API which allows you to process events synchronously. But sync$()
comes with a few caveats:
sync$()
can't close over any state.sync$()
can't call other functions which are declared in scope or imported.sync$()
is serialized into HTML and therefore we should be conscious of the size of the function.
A typical way to deal with these limitations is to split the event handling into two parts:
sync$()
which is called synchronously and can call methods such asevent.preventDefault()
andevent.stopPropagation()
.$()
which is called asynchronously and can close over the state and call other functions, and has no restriction on the size.
Because sync$()
can't access the state what is the best strategy to deal with it? The answer is to use element attributes to pass state into the sync$()
function.
NOTE: If you only need to prevent the default behavior, you can simply use the standard
preventDefault:{eventName}
syntax. This is strictly for when you need to chain events together synchronously
sync$()
with state
Example: In this example, we have a behavior where we want to prevent the default behavior of the link based on some state. We do this by breaking the code into three parts:
sync$()
: a synchronous portion that is kept to the minimum,$()
: an asynchronous portion that can be arbitrarily large, and can close over state,data-should-prevent-default
: an attribute on the element that is used to pass state into thesync$()
function.
import { component$, useSignal, sync$, $ } from '@builder.io/qwik';
export default component$(() => {
const shouldPreventDefault = useSignal(true);
return (
<div>
<div>Sync Event:</div>
<input
type="checkbox"
checked={shouldPreventDefault.value}
onChange$={(e, target) =>
(shouldPreventDefault.value = target.checked)
}
/>{' '}
Should Prevent Default
<hr />
<a
href="https://google.com"
target="_blank"
data-should-prevent-default={shouldPreventDefault.value}
onClick$={[
sync$((e: MouseEvent, target: HTMLAnchorElement) => {
if (target.hasAttribute('data-should-prevent-default')) {
e.preventDefault();
}
}),
$(() => {
console.log(
shouldPreventDefault.value ? 'Prevented' : 'Not Prevented'
);
}),
]}
>
open Google
</a>
</div>
);
});