Skip to content

Commit

Permalink
fix: avoid writing to state in media-query getter (#122)
Browse files Browse the repository at this point in the history
  • Loading branch information
paoloricciuti authored Jul 27, 2024
1 parent 296c835 commit b1b4770
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 12 deletions.
5 changes: 5 additions & 0 deletions .changeset/hot-feet-hang.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"runed": patch
---

fix: avoid writing to state in media-query getter
23 changes: 11 additions & 12 deletions packages/runed/src/lib/utilities/MediaQuery/MediaQuery.svelte.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useEventListener } from "../useEventListener/useEventListener.svelte.js";
import { extract } from "../extract/extract.js";
import { useEventListener } from "../useEventListener/useEventListener.svelte.js";
import type { MaybeGetter } from "$lib/internal/types.js";
import { browser } from "$lib/internal/utils/browser.js";

/**
* Takes a media query as an input and listsens for changes to it,
Expand Down Expand Up @@ -38,35 +37,35 @@ export class MediaQuery {
#propQuery: MaybeGetter<string>;
#query = $derived.by(() => extract(this.#propQuery));
#mediaQueryList: MediaQueryList = $derived(window.matchMedia(this.#query));
#effectRegistered = false;
#effectRegistered = 0;
#matches: boolean | undefined = $state();

constructor(query: MaybeGetter<string>) {
this.#propQuery = query;
}

get matches(): boolean | undefined {
if ($effect.tracking() && !this.#effectRegistered) {
this.#matches = this.#mediaQueryList.matches;

if ($effect.tracking() && this.#effectRegistered === 0) {
// If we are in an effect and this effect has not been registered yet
// we match the current value, register the listener and return match
$effect(() => {
this.#effectRegistered = true;
this.#effectRegistered++;

useEventListener(
() => this.#mediaQueryList,
"change",
(changed) => (this.#matches = changed.matches)
);

return () => (this.#effectRegistered = false);
return () => {
this.#effectRegistered--;
// if we deregister the event it means it's not used in any component
// and we want to go back to use the value from `this.#mediaQueryList.matches`
this.#matches = undefined;
};
});
} else if (!$effect.tracking() && browser) {
// Otherwise, just match media to get the current value
this.#matches = this.#mediaQueryList.matches;
}

return this.#matches;
return this.#matches ?? this.#mediaQueryList.matches;
}
}

0 comments on commit b1b4770

Please sign in to comment.