Skip to content

Commit

Permalink
fix: address bug in before/after update (#9448)
Browse files Browse the repository at this point in the history
* fix: address bug in before/after update

fix: address bug in before/after update

* Add changeset

* use every instead of filter - more explicit and enables early-exit from the loop

* Update logic and comment

---------

Co-authored-by: Rich Harris <rich.harris@vercel.com>
  • Loading branch information
trueadm and Rich-Harris committed Nov 15, 2023
1 parent f5101c0 commit 9eb969d
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 3 deletions.
5 changes: 5 additions & 0 deletions .changeset/nasty-clocks-exercise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

fix: corrects a beforeUpdate/afterUpdate bug
14 changes: 11 additions & 3 deletions packages/svelte/src/internal/client/runtime.js
Original file line number Diff line number Diff line change
Expand Up @@ -960,10 +960,18 @@ export function set_signal_value(signal, value) {
schedule_effect(current_effect, false);
}
mark_signal_consumers(signal, DIRTY, true);
// If we have afterUpdates locally on the component, but we're within a render effect
// then we will need to manually invoke the beforeUpdate/afterUpdate logic.
// This logic checks if there are any render effects queued after the above marking
// of consumers. If there are render effects that have the same component context as
// the source signal we're writing to, then we can bail-out of this logic as there
// will be a render effect in the queue that hopefully takes case of triggering the
// beforeUpdate/afterUpdate logic (doing it again here would duplicate them). However,
// if the render effects scheduled in the queue are unrelated to the component context,
// then we need to trigger the beforeUpdate/afterUpdate logic here instead.
// TODO: should we put this being a is_runes check and only run it in non-runes mode?
if (current_effect === null && current_queued_pre_and_render_effects.length === 0) {
if (
current_effect === null &&
current_queued_pre_and_render_effects.every((e) => e.context !== component_context)
) {
const update_callbacks = component_context?.update_callbacks;
if (update_callbacks != null) {
update_callbacks.before.forEach(/** @param {any} c */ (c) => c());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<script>
const {count, increment} = $props();
</script>

<button onclick={increment}>
{count}
</button>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { flushSync } from 'svelte';
import { test } from '../../test';

export default test({
html: '<button>0</button>',

async test({ assert, target, component }) {
const [btn] = target.querySelectorAll('button');
flushSync(() => {
btn.click();
});
assert.deepEqual(component.log, ['beforeUpdate', 'afterUpdate']);
assert.htmlEqual(target.innerHTML, `<button>1</button>`);
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<script>
import Child from './Child.svelte'
import {afterUpdate, beforeUpdate} from 'svelte';
const {log = []} = $props();
let count = $state(0);
const increment = () => {
count++;
}
beforeUpdate(() => {
log.push('beforeUpdate');
});
afterUpdate(() => {
log.push('afterUpdate');
});
</script>

<Child count={count} increment={increment} />

1 comment on commit 9eb969d

@vercel
Copy link

@vercel vercel bot commented on 9eb969d Nov 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

svelte-5-preview – ./sites/svelte-5-preview

svelte-5-preview-svelte.vercel.app
svelte-5-preview-git-main-svelte.vercel.app
svelte-octane.vercel.app
svelte-5-preview.vercel.app

Please sign in to comment.