Effect.ts: Absence as First-Class
State Management • Lesson 49 of 51
30. Ref: update vs set
When to transform the current value vs. replace it completely
The Difference
const counter = yield* Ref.make(10);
// set: "I don't care what it was, make it 42"
yield* Ref.set(counter, 42);
// counter is now 42
// update: "Take what it is, and add 5"
yield* Ref.update(counter, n => n + 5);
// counter is now 47
Ref.set(ref, newValue)Use when: You want to replace the value completely, ignoring what was there.
const status = yield* Ref.make("idle");
// User clicked "start"
yield* Ref.set(status, "running");
// Task finished
yield* Ref.set(status, "completed");
Pattern: New value doesn't depend on old value.
Ref.update(ref, fn)Use when: You want to transform based on the current value.
const counter = yield* Ref.make(0);
// Increment
yield* Ref.update(counter, n => n + 1);
// Double it
yield* Ref.update(counter, n => n * 2);
// Add 10
yield* Ref.update(counter, n => n + 10);
Pattern: New value = fn(oldValue)
Real Example: Shopping Cart
const cart = Effect.gen(function* () {
const items = yield* Ref.make<string[]>([]);
// Add items (transform current array)
yield* Ref.update(items, arr => [...arr, "apple"]);
yield* Ref.update(items, arr => [...arr, "banana"]);
yield* Ref.update(items, arr => [...arr, "orange"]);
console.log(yield* Ref.get(items));
// ["apple", "banana", "orange"]
// Clear cart (replace with empty)
yield* Ref.set(items, []);
console.log(yield* Ref.get(items));
// []
});
Common Patterns
Counters → use update
yield* Ref.update(count, n => n + 1); // increment
yield* Ref.update(count, n => n - 1); // decrement
yield* Ref.update(count, n => n * 2); // double
Status/Flags → use set
yield* Ref.set(isLoading, true);
yield* Ref.set(status, "error");
yield* Ref.set(mode, "dark");
Arrays/Objects → use update
yield* Ref.update(todos, arr => [...arr, newTodo]);
yield* Ref.update(user, u => ({ ...u, age: 30 }));
Reset → use set
yield* Ref.set(cart, []);
yield* Ref.set(counter, 0);
yield* Ref.set(errors, null);
Quick Decision Tree
Do you need the current value?
├─ YES → use Ref.update()
└─ NO → use Ref.set()
Bonus:
updateAndGetWant to update AND get the new value in one shot?
const newValue = yield* Ref.updateAndGet(counter, n => n + 1);
console.log(newValue); // New value after update
Saves you from doing:
yield* Ref.update(counter, n => n + 1);
const newValue = yield* Ref.get(counter);
Choose the right tool: set for replacement, update for transformation
Part 49 of 51 in the Effect.ts Absence Modeling series