Synchronous Events with sync()
While not a common use case, you may occasionally need to process events synchronously.
The two most common use cases are to call event.preventDefault()
or event.stopPropagation()
on a DOM event. Those are handled by adding the preventdefault:eventname
or stoppropagation:eventname
in addition to your event handler.
<a href="/" preventdefault:click onClick$={() => {
console.log('clicked');
}}>
link
</a>
When you have other use cases that require synchronous event processing, you can use either sync$()
or useVisibleTask$()
.
- preferred way: use
sync$()
to embed the code in the HTML. Fast, resumable, but with some restrictions (see below). - eager registration: use
useVisibleTask$()
to register a handler. No restrictions, but it will not handle events until the visible task has executed, and it will cause of course run extra javaScript while the page is loading.
<a href="/"
onClick$={sync$((event, target) => {
// Only prevent default if the ctrl key is pressed.
if (event.ctrlKey) {
event.preventDefault();
}
})}>
link
</a>
sync$()
Restrictions
The sync$()
function is a resumable way to process events synchronously. However, it has some significant restrictions. The sync$()
can't close over anything. The implications are that you can't:
- access any state: The recommended way to get the state into function is to place on element attributes.
- access any non-browser functions: No imports or closing over any variables or functions are allowed.
- the function should be small as it will get inlined into the resulting HTML.
For this reason, we recommended breaking up the event handlers into two parts:
- sync$(): The part which must be synchronous. This part should be small and not close over anything.
- $(): The part which can be asynchronous. This part can be large and can close over anything including the state.
<a href="/"
onClick$={[
sync$((event, target) => {
// This part is synchronous and can't close over anything.
if (event.ctrlKey) {
event.preventDefault();
}
}),
$(() => {
// This part can be asynchronous and can close over anything.
console.log('clicked');
})
]}>
link
</a>
You can also dispatch a custom event from the sync$()
handler and handle it asynchronously:
<a href="/"
onClick$={sync$((event, target) => {
if (event.ctrlKey) {
event.preventDefault();
}
// Dispatch a custom event to be handled asynchronously.
target.dispatchEvent(new CustomEvent('myclick', { bubbles: true }));
})}
onMyclick$={() => {
// This part can be asynchronous and can close over anything.
console.log('clicked');
}}>
link
</a>
Your task: Convert the onClick$
from asynchronous event to synchronous event by using sync$
.