Untracked выполнение

Untracked — это механизм Solid.js, позволяющий выполнять функцию без создания реактивных зависимостей. Он необходим в ситуациях, когда требуется избежать автоматического подписывания на сигналы, чтобы предотвратить ненужные перерендеры и повысить производительность.

Основная концепция

В Solid.js реактивность строится вокруг сигналов (createSignal) и эффектов (createEffect). Обычно при чтении сигнала внутри эффекта автоматически создаётся зависимость, и эффект будет повторно вызываться при изменении сигнала. Иногда требуется выполнить код, который читает сигналы, но не должен становиться зависимым от их изменений. Для этого используется untrack.

import { createSignal, untrack } from "solid-js";

const [count, setCount] = createSignal(0);

const value = untrack(() => count()); // Чтение без подписки

В этом примере value получит текущее значение count, но не будет автоматически обновляться при последующих изменениях сигнала.

Практическое использование

  1. Чтение значений внутри эффекта без подписки Иногда необходимо использовать значения сигналов в эффекте, но не создавать зависимость, чтобы эффект запускался только по другим причинам:
import { createSignal, createEffect, untrack } from "solid-js";

const [count, setCount] = createSignal(0);
const [trigger, setTrigger] = createSignal(false);

createEffect(() => {
  console.log("Effect triggered by trigger:", trigger());
  
  const currentCount = untrack(() => count());
  console.log("Current count (untracked):", currentCount);
});

setCount(1); // Не вызовет эффект
setTrigger(true); // Вызовет эффект

Здесь count читается без создания зависимости, поэтому изменение его значения не перезапускает эффект.

  1. Внутри вычисляемых сигналов (createMemo) Иногда нужно создать вычисление, которое частично зависит от сигналов, но некоторые данные должны быть получены без подписки:
import { createSignal, createMemo, untrack } from "solid-js";

const [a, setA] = createSignal(1);
const [b, setB] = createSignal(2);

const memo = createMemo(() => {
  const untrackedB = untrack(() => b());
  return a() + untrackedB;
});

console.log(memo()); // 3
setB(5);
console.log(memo()); // 3, не изменилось
setA(3);
console.log(memo()); // 8, обновилось только по изменению a

untrack позволяет выборочно отключить реактивность для определённых сигналов, оставляя остальные зависимости активными.

Разница между untrack и чистым чтением

Без untrack любое чтение сигнала внутри реактивного контекста создаёт зависимость. Это полезно для автоматического обновления интерфейса, но иногда приводит к лишним ререндерингам. untrack даёт точечный контроль:

  • С untrack: сигнал читается как обычное значение, без подписки.
  • Без untrack: сигнал становится зависимостью текущего эффекта или мемо.

Внутренний механизм

untrack работает, временно отключая текущий реактивный контекст. Solid.js хранит стек эффектов, и untrack выполняет функцию в контексте, где стек очистлен, поэтому чтение сигналов не создаёт подписок. После выполнения стек восстанавливается, и последующие чтения снова становятся реактивными.

function untrack(fn) {
  const prev = getListener(); // Сохраняем текущий эффект
  setListener(null);           // Отключаем реактивный контекст
  try {
    return fn();
  } finally {
    setListener(prev);         // Восстанавливаем эффект
  }
}

Рекомендации по использованию

  • Использовать для оптимизации производительности при чтении сигналов, значения которых не должны триггерить эффекты.
  • Полезно в больших вычислениях или при комбинировании сигналов с внешними данными.
  • Избегать избыточного использования: если отключать реактивность слишком часто, код может стать трудно предсказуемым.

untrack — инструмент тонкой настройки реактивности. Он позволяет избежать лишних перерендеров, сохраняя высокую скорость и детерминированность работы приложений Solid.js.