Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow usage of getContext() within $derived runes #13830

Merged
merged 4 commits into from
Oct 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/beige-llamas-grab.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

feat: allow usage of getContext() within $derived runes
2 changes: 1 addition & 1 deletion packages/svelte/src/internal/client/dom/elements/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ export function apply(

if (typeof handler === 'function') {
handler.apply(element, args);
} else if (has_side_effects || handler != null) {
} else if (has_side_effects || handler != null || error) {
const filename = component?.[FILENAME];
const location = loc ? ` at ${filename}:${loc[0]}:${loc[1]}` : ` in ${filename}`;

Expand Down
6 changes: 4 additions & 2 deletions packages/svelte/src/internal/client/reactivity/deriveds.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ import {
skip_reaction,
update_reaction,
increment_version,
set_active_effect
set_active_effect,
component_context
} from '../runtime.js';
import { equals, safe_equals } from './equality.js';
import * as e from '../errors.js';
Expand All @@ -44,6 +45,7 @@ export function derived(fn) {
/** @type {Derived<V>} */
const signal = {
children: null,
ctx: component_context,
deps: null,
equals,
f: flags,
Expand Down Expand Up @@ -169,5 +171,5 @@ export function destroy_derived(signal) {
set_signal_status(signal, DESTROYED);

// TODO we need to ensure we remove the derived from any parent derives
signal.v = signal.children = signal.deps = signal.reactions = null;
signal.v = signal.children = signal.deps = signal.ctx = signal.reactions = null;
}
4 changes: 2 additions & 2 deletions packages/svelte/src/internal/client/reactivity/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ export interface Value<V = unknown> extends Signal {
}

export interface Reaction extends Signal {
/** The associated component context */
ctx: null | ComponentContext;
/** The reaction function */
fn: null | Function;
/** Signals that this signal reads from */
Expand All @@ -40,8 +42,6 @@ export interface Effect extends Reaction {
*/
nodes_start: null | TemplateNode;
nodes_end: null | TemplateNode;
/** The associated component context */
ctx: null | ComponentContext;
/** Reactions created inside this signal */
deriveds: null | Derived[];
/** The effect function */
Expand Down
5 changes: 3 additions & 2 deletions packages/svelte/src/internal/client/runtime.js
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ export function update_reaction(reaction) {
var previous_reaction = active_reaction;
var previous_skip_reaction = skip_reaction;
var prev_derived_sources = derived_sources;
var previous_component_context = component_context;
var flags = reaction.f;

new_deps = /** @type {null | Value[]} */ (null);
Expand All @@ -310,6 +311,7 @@ export function update_reaction(reaction) {
active_reaction = (flags & (BRANCH_EFFECT | ROOT_EFFECT)) === 0 ? reaction : null;
skip_reaction = !is_flushing_effect && (flags & UNOWNED) !== 0;
derived_sources = null;
component_context = reaction.ctx;

try {
var result = /** @type {Function} */ (0, reaction.fn)();
Expand Down Expand Up @@ -347,6 +349,7 @@ export function update_reaction(reaction) {
active_reaction = previous_reaction;
skip_reaction = previous_skip_reaction;
derived_sources = prev_derived_sources;
component_context = previous_component_context;
}
}

Expand Down Expand Up @@ -422,7 +425,6 @@ export function update_effect(effect) {
var previous_component_context = component_context;

active_effect = effect;
component_context = effect.ctx;

if (DEV) {
var previous_component_fn = dev_current_component_function;
Expand All @@ -449,7 +451,6 @@ export function update_effect(effect) {
handle_error(/** @type {Error} */ (error), effect, previous_component_context);
} finally {
active_effect = previous_effect;
component_context = previous_component_context;

if (DEV) {
dev_current_component_function = previous_component_fn;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<script>
import { getContext } from 'svelte'

let count = $state(0);
let total = $derived(multiply(count));

function multiply(num) {
const context = getContext("key");
return num * context;
}
</script>

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

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

test({ assert, target }) {
const btn = target.querySelector('button');

flushSync(() => {
btn?.click();
});

assert.htmlEqual(target.innerHTML, `<button>10</button>`);
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<script>
import { setContext } from 'svelte'
import Child from './Child.svelte'
setContext("key", 10)
</script>

<Child />

Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,24 @@ export default test({
},

test({ assert, target, warnings }) {
/** @type {any} */
let error;

const handler = (/** @type {any}} */ e) => {
error = e.error;
e.stopImmediatePropagation();
};

window.addEventListener('error', handler, true);

target.querySelector('button')?.click();

assert.throws(() => {
throw error;
}, /state_unsafe_mutation/);

window.removeEventListener('error', handler, true);

assert.deepEqual(warnings, [
'`click` handler at Button.svelte:5:9 should be a function. Did you mean to add a leading `() =>`?'
]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,24 @@ export default test({
},

test({ assert, target, warnings }) {
/** @type {any} */
let error;

const handler = (/** @type {any} */ e) => {
error = e.error;
e.stopImmediatePropagation();
};

window.addEventListener('error', handler, true);

target.querySelector('button')?.click();

assert.throws(() => {
throw error;
}, /state_unsafe_mutation/);

window.removeEventListener('error', handler, true);

assert.deepEqual(warnings, [
'`click` handler at main.svelte:9:17 should be a function. Did you mean to remove the trailing `()`?'
]);
Expand Down