Skip to content

Commit

Permalink
fix(refresh): don't reset scheduled timeout if a rerender occurs
Browse files Browse the repository at this point in the history
  • Loading branch information
lowlighter committed Nov 25, 2024
1 parent 9a6de07 commit 0a37b7a
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 5 deletions.
4 changes: 2 additions & 2 deletions @mizu/refresh/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Reprocess an element at a specified interval _(in seconds)_.
## Notes

> [!WARNING]
> Context is recreated from the initial root context and the element itself, meaning intermediate computations are not retained. Use this only on elements that can be rendered independently to avoid unexpected errors.
> Ensure proper context management to prevent unexpected errors.
> [!WARNING]
> Avoid using with iterative directives like [`*for`](#for) as [`*refresh`](#refresh) will be duplicated for each generated element.
Expand All @@ -36,4 +36,4 @@ Reprocess an element at a specified interval _(in seconds)_.

### `$refresh: boolean`

A flag that indicates whether the element is being refreshed.
Indicates if the element is currently being refreshed.
10 changes: 7 additions & 3 deletions @mizu/refresh/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export const _refresh = {
// Clear interval if value is null
if (value === null) {
clearTimeout(cache.get(element)?.id)
cache.delete(element)
return
}

Expand All @@ -30,8 +31,11 @@ export const _refresh = {
renderer.warn(`[${this.name}] expects a finite positive number but got ${value}, ignoring`, element)
return
}
clearTimeout(cache.get(element)?.id)
cache.set(element, { interval, id: NaN })
const cached = cache.get(element) ?? cache.set(element, { interval, id: NaN }).get(element)!
if (((cached.interval !== interval) && (!Number.isNaN(cached.id))) || (options.state[renderer.internal("refreshing")])) {
clearTimeout(cached.id)
cached.id = NaN
}
},
cleanup(renderer, element, { cache, ...options }) {
// Cleanup interval from commented out elements
Expand All @@ -48,7 +52,7 @@ export const _refresh = {
}
cache.get(element)!.id = setTimeout(() => {
if (element.isConnected) {
renderer.render(element as HTMLElement, { ...options, state: { ...options.state, $refresh: true } })
renderer.render(element as HTMLElement, { ...options, state: { ...options.state, $refresh: true, [renderer.internal("refreshing")]: true } })
}
}, cache.get(element)!.interval)
},
Expand Down
35 changes: 35 additions & 0 deletions @mizu/refresh/mod_test.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
context.foo = fn()
await delay(context.interval * 1000)
expect(context.foo).toHaveBeenCalled()
context.foo = fn()
await delay(context.interval * 1000)
expect(context.foo).toHaveBeenCalled()
</script>
<script>
context.interval = .105
Expand All @@ -21,6 +24,9 @@
context.foo = fn()
await delay(context.interval * 1000)
expect(context.foo).toHaveBeenCalled()
context.foo = fn()
await delay(context.interval * 1000)
expect(context.foo).toHaveBeenCalled()
</script>
<render></render>
<script>
Expand All @@ -34,6 +40,35 @@
</script>
</test>

<test name="[*refresh] does not reset upon normal rerenderings">
<script>
context.foo = () => null
context.interval = .100
</script>
<render>
<p *refresh="(foo(), interval)"></p>
</render>
<script>
context.foo = fn()
storage.loop = true
await Promise.race([
delay(context.interval * 1000),
new Promise(async () => {
while (storage.loop) {
await rerender()
await delay(.001)
}
}),
])
storage.loop = false
expect(context.foo).toHaveBeenCalled()
</script>
<script>
context.interval = null
</script>
<render></render>
</test>

<test name="[*refresh] handles commented elements">
<script>
context.value = true
Expand Down

0 comments on commit 0a37b7a

Please sign in to comment.