No-Hydration Tips

Don't register events eagerly with useClientEffect$()

โš  Use useClientEffect$() with caution โš 

Instead => useOn() methods

Best Practice:

useClientEffect$(()=> {
    const listener = (event)=> {
        const mouseEvent = event as MouseEvent
        console.log(mouseEvent.x, mouseEvent.y);
    document.addEventListener('mousemove', listener);

    return ()=> {document.removeEventListener(listener)}

Why is above a problem: This forces more javascript to eagerly load, rather than be surgically reactive to user events. More upfront javascript => slower app performance.

It also requires you, the developer, to stay more aware of the server/client relationship (there's a reason you reached for use >Client< Effect after all).

While that's sometimes necessary, it should be the job of the framework to keep you from having to worry about it as much as possible.

Not to mention it requires the extra effort for you to manually clean up the listener.

Do this instead:

useOnDocument('mousemove', $((event)=> {
    const mouseEvent = event as MouseEvent;
    console.log(mouseEvent.x, mouseEvent.y)
    // No manual clean up required!

NOTE: Similar hooks exist for window and individual components.
window -> useOnWindow , component -> useOn

Don't rely on window to get the location

Instead => useLocation()

Best Practice:

useClientEffect$(()=> {
    if (window.location.href).includes('foo') {
        //... do the thing


//(in the root of a component)
if (typeof window !== "undefined") {
    const queryParams = new URLSearchParams(;
    const query: Record<string, string> = {};
    queryParams.forEach((value, key) => {
        query[key] = value;

Why is above a problem: Many, many things you'll do in response to location information can easily be done on the initial render on the server, and will result in pure HTML with no JS overhead.

If you force that logic to instead run on the client side, it introduces more upfront JS & causes an eager load.

When using the if typeof window !== "undefined" pattern you'll soon find it will simply skip that code. It will run one time on the server and skip the code block because window will always be undefined on the server. You're used to code running twice. Qwik doesn't need to! ๐Ÿ˜Ž

Do this instead:

const location = useLocation();

if (location.href.includes('foo')) {
    // Do the thing


When doing SSG for pure static files, this is a necessary evil. The server won't have current location information when the server generates the files at build time.

But be mindful! If the information you need (e.g., query parameters) won't be necessary until some sort of user event, include the check in your event handling code instead to avoid the eager loading of JS.

See: useLocation() Docs

Made with โค๏ธ by