Приведенный ниже код работает так, как должен, я просто пытаюсь лучше понять, почему.
Насколько getCurrentElement
метод TestState
реактивен без использования $derived()
? Являются ли методы хранилища, использующие состояние, реактивными по умолчанию?
Я использую [email protected]
test-store.svelte.ts
import { getContext, setContext } from 'svelte';
class TestState {
elements = [
{
id: 'hghxt',
name: 'Give',
},
{
id: 'vhtl9',
name: 'Connection',
},
{
id: '5n0t0',
name: 'Take notice',
},
{
id: 'xlfba',
name: 'Keep learning',
},
{
id: '1f3z2',
name: 'Be active',
},
];
#currentElementId = $state<string>();
getCurrentElement() {
return this.elements.find(element => element.id === this.#currentElementId);
}
setCurrentElement(id: string) {
if (!this.elements.some(element => element.id === id)) return;
this.#currentElementId = id;
}
}
const TEST_STORE_KEY = Symbol('TEST_STORE');
export function setTestState() {
return setContext(TEST_STORE_KEY, new TestState());
}
export function getTestState() {
return getContext<ReturnType<typeof setTestState>>(TEST_STORE_KEY);
}
TestComponent.svelte
<script lang = "ts">
import { getTestState } from '$lib/stores/test-store.svelte';
// initialised at +page.svelte
const testState = getTestState();
</script>
{#each testState.elements as { name, id }}
<button
class:bg-yellow = {testState.getCurrentElement()?.id === id}
onclick = {() => testState.setCurrentElement(id)}>
{name}
</button>
{/each}
В своем «HTML-коде» вы называете testState.getCurrentElement()
. Когда вы это сделаете, Svelte заметит, от каких реактивных переменных зависит этот вызов. В getCurrentElement()
вы получаете доступ к this.#currentElementId
, поэтому Svelte знает, что эту часть «HTML-кода» необходимо повторно отобразить/обновить, когда this.#currentElementId
присвоено новое значение.
Вам нужно использовать $derived()
только тогда, когда вы хотите автоматически вычислить новое значение, как только реактивная переменная изменит значение, и здесь это не тот случай, поэтому я не вижу здесь никакого смысла использовать $derived()
.
@JackTempleman, возможно, мы называем вещи по-разному, но такого понятия, как реактивная функция, не существует, по крайней мере, в моем словаре. У нас есть только реактивные переменные/выражения, которые можно создать с помощью некоторых рун, например $state()
. Если одна из ваших функций использует реактивную переменную/выражение, то сама эта функция не является реактивной; это просто функция, которая использует реактивные переменные/выражения. Только создание такой функции не приведет к самостоятельным пересчетам. Но если вы вызываете/используете такую функцию в некоторых местах, где Svelte отслеживает реактивность (например, в HTML-коде компонента или в некоторых рунах), тогда Svelte узнает о реактивных переменных/выражениях, которые использует функция, и Svelte вызовет функция снова в будущем, когда эти реактивные переменные/выражения изменят значение.
Делает ли это, по сути, любую функцию, использующую состояние, обратным вызовом $derived.by
?
Нет, я так не думаю. Если бы это было так, то весь код, который вы пишете, был бы реактивным, а это не так: код JS верхнего уровня в компоненте не является реактивным, и его нужно поместить в какую-то руну для повторного запуска всякий раз, когда назначается используемая им реактивная переменная. новое значение. Svelte реагирует только в некоторых местах (например, в HTML-коде и в некоторых рунах).
Но этот вопрос предполагает, что если это функция и она просто использует руну, она становится реактивной? Оба этих утверждения являются реактивными, когда selectedElementId
определяется с использованием $state. const selectedElementFunction = () => elements.find(ele => ele.id === selectedElementId);
и const selectedElementDerived = $derived(elements.find(ele => ele.id === selectedElementId));
@PeppeL-G: $derived
ленив, он пересчитывает только при использовании (пример). Основная причина использования $derived
— кэширование дорогостоящих вычислений.
@JackTempleman, см. обновленный ответ. Хотя не уверен, что это прояснит ситуацию. И, как отметил @brunnerh, $derived()
может повысить производительность.
Возможно, это прояснит ситуацию: const selectedElementFunction = () => elements.find(ele => ele.id === selectedElementId);
никогда не будет вызывать перерасчеты сам по себе. Это произойдет только в том случае, если вы вызовете его из своего HTML-кода или из руны (например, $derived
). Если вы вызовете его на верхнем уровне JS в файле Svelte, он никогда не вызовет повторные вычисления из-за этого вызова.
Понятно. Таким образом, Svelte распознает, когда функция использует состояние, добавляет ее в качестве зависимости и повторно запускает функцию при обновлении ее зависимостей. Отличный ДХ.