Derived Values with createMemo
When a plain derived function is enough, and when createMemo's caching actually earns its keep.
읽는 데 2분
Once you have a signal, you'll often want a value computed from it — a filtered list, a formatted string, a total. Solid gives you two ways to do this, and knowing which to reach for matters more than it first appears.
The simplest option: a plain function
function Cart() {
const [items, setItems] = createSignal([
{ name: "Book", price: 12 },
{ name: "Pen", price: 2 },
]);
const total = () => items().reduce((sum, item) => sum + item.price, 0);
return <p>Total: ${total()}</p>;
}total here is just a regular function, not a signal. Every time something reads total() inside a reactive context, it re-runs the calculation from scratch using the current items(). For cheap computations, this is perfectly fine — and it's the default you should reach for first.
createMemo: cache the result, recompute only on change
import { createMemo } from "solid-js";
function Cart() {
const [items, setItems] = createSignal([
{ name: "Book", price: 12 },
{ name: "Pen", price: 2 },
]);
const total = createMemo(() =>
items().reduce((sum, item) => sum + item.price, 0)
);
return (
<>
<p>Total: ${total()}</p>
<p>Total again: ${total()}</p>
</>
);
}createMemo wraps a function and returns a signal-like getter. The difference from the plain-function version: the calculation inside runs once per dependency change, and every subsequent read of total() — no matter how many places read it — returns the cached result instantly, rather than recomputing. In the example above, reading total() twice in the plain-function version reduces the array twice; with createMemo, it reduces once and both reads share the cached value.
When the difference actually matters
For a three-item cart, you won't notice a thing either way. createMemo earns its cost when:
- The computation is genuinely expensive (sorting a large list, heavy string processing).
- The derived value is read from multiple places in your UI, and you don't want to redo the work for each one.
- You want the derived value to only recompute when its actual dependencies change, isolating it from unrelated reactive updates nearby.
A common mistake: memoizing too eagerly
// Unnecessary — doubling a number is essentially free
const doubled = createMemo(() => count() * 2);
// This is fine as a plain function; no caching benefit to justify the overhead
const doubled = () => count() * 2;createMemo isn't free — it sets up its own tracking scope and comparison logic. Wrapping every derived value in it "just in case" adds overhead without benefit for cheap computations. Start with a plain function; reach for createMemo when you can point to a real reason (expensive work, or multiple readers) to justify the caching.