Производные значения и createMemo
Производное значение — это то, что вычисляется из других данных: количество невыполненных задач, отфильтрованный список, полное имя из имени и фамилии. Хранить его в отдельном сигнале не нужно, достаточно описать, как его получить.
Производная функция
Самый простой способ — обычная стрелочная функция, которая читает сигналы:
// src/components/Counter.jsx
import { createSignal } from 'solid-js';
export default function Counter() {
const [count, setCount] = createSignal(0);
const doubled = () => count() * 2;
return (
<div>
<p>Задач: {count()}, в два раза больше: {doubled()}</p>
<button onClick={() => setCount(count() + 1)}>Добавить</button>
</div>
);
}При нажатии оба числа обновляются. doubled — функция, поэтому её, как и сигнал, вызывают: doubled(). Вызов внутри JSX читает count(), и Solid отслеживает эту зависимость.
createMemo
Производная функция выполняется каждый раз, когда её вызывают. Если вычисление тяжёлое или результат используется во многих местах, его кешируют через createMemo:
// src/components/TodoStats.jsx
import { createSignal, createMemo } from 'solid-js';
export default function TodoStats() {
const [todos, setTodos] = createSignal([
{ id: 1, title: 'Купить молоко', done: true },
{ id: 2, title: 'Позвонить Олегу', done: false },
]);
const left = createMemo(() => todos().filter((t) => !t.done).length);
const add = () => {
setTodos([...todos(), { id: Date.now(), title: 'Новая задача', done: false }]);
};
return (
<div>
<p>Осталось: {left()}</p>
<p>Всего: {todos().length}</p>
<button onClick={add}>Добавить</button>
</div>
);
}На странице «Осталось: 1» и «Всего: 2»; каждое нажатие увеличивает оба числа. createMemo пересчитывает фильтр только при изменении todos, а между изменениями отдаёт сохранённый результат.
Что выбрать
| Способ | Когда подходит |
|---|---|
const x = () => ... | Простое вычисление, одно-два места использования |
createMemo(() => ...) | Тяжёлое вычисление или много читателей |
Начинайте с функции. Переходите на createMemo, когда видите, что одно и то же считается много раз.
Memo тоже возвращает функцию
Результат createMemo читается вызовом, как сигнал: left(). Его можно передавать в пропсы и использовать внутри других memo — зависимости выстроятся в цепочку автоматически.
Частая ошибка
Дублировать производное значение в отдельном сигнале и обновлять его вручную:
// src/components/TodoStats.jsx
import { createSignal, createEffect } from 'solid-js';
export default function TodoStats() {
const [todos, setTodos] = createSignal([]);
// Лишнее: второй сигнал и эффект для синхронизации
const [total, setTotal] = createSignal(0);
createEffect(() => setTotal(todos().length));
return <p>Всего: {total()}</p>;
}Такой код сложнее и может показать устаревшее значение. Достаточно const total = () => todos().length.