diff --git a/docs/api/reactivity-utility.md b/docs/api/reactivity-utility.md index 9e441c2..4597364 100644 --- a/docs/api/reactivity-utility.md +++ b/docs/api/reactivity-utility.md @@ -50,3 +50,35 @@ Runs a callback anytime a function scope is re-ran. return label end) ``` + +## untrack() + +Gets the value of a source without reactively tracking it. + +- **Type** + + ```lua + function untrack(source: () -> T): T + ``` + +- **Details** + + Updates made to a source passed to `untrack()` will not cause updates to + anything depending on that source. + +- **Example** + + ```lua + local a = source(0) + local b = source(0) + + local sum = derive(function() + return a() + untrack(b) + end) + + print(sum()) -- 0 + b(1) + print(sum()) -- 0 + a(1) + print(sum()) -- 2 + ``` diff --git a/src/graph.luau b/src/graph.luau index 025f8bf..3aef02a 100644 --- a/src/graph.luau +++ b/src/graph.luau @@ -159,4 +159,5 @@ return table.freeze { capture = capture, capture_and_link = capture_and_link, create = create :: ((value: T) -> (Node, () -> T)) & (() -> (Node, () -> T)), + refs = refs } diff --git a/src/init.luau b/src/init.luau index cde7428..c4665b2 100644 --- a/src/init.luau +++ b/src/init.luau @@ -9,6 +9,7 @@ local create = require(script.create) local source = require(script.source) local watch = require(script.watch) local cleanup, clean_garbage = require(script.cleanup)() +local untrack = require(script.untrack) local derive = require(script.derive) local indexes, values = require(script.maps)() local spring, update_springs = require(script.spring)() @@ -23,11 +24,14 @@ local vide = { create = create, source = source, watch = watch, - cleanup = cleanup, derive = derive, indexes = indexes, values = values, + -- util + cleanup = cleanup, + untrack = untrack, + -- animations spring = spring, diff --git a/src/untrack.luau b/src/untrack.luau new file mode 100644 index 0000000..4aa744f --- /dev/null +++ b/src/untrack.luau @@ -0,0 +1,16 @@ +if not game then script = require "test/relative-string" end + +local graph = require(script.Parent.graph) +type Node = graph.Node +local refs = graph.refs + +local function untrack(source: () -> T): T + local initial = #refs + local value = source() + for i = initial, #refs do + refs[i] = nil + end + return value +end + +return untrack diff --git a/test/tests.luau b/test/tests.luau index 04a9157..699d262 100644 --- a/test/tests.luau +++ b/test/tests.luau @@ -1260,6 +1260,58 @@ TEST("spring()", function() end end) +TEST("untrack()", function() + local source = vide.source + local watch = vide.watch + local untrack = vide.untrack + + do CASE "does not register dependency" + local a = source(0) + local b = source(0) + + local count = -1 + + watch(function() + count += 1 + untrack(a) + b() + end) + + b(1) + CHECK(count == 1) + + a(1) + CHECK(count == 1) + + CHECK(a() == untrack(a)) + end + + do CASE "derived state" + local a = source(0) + local b = source(0) + local c = source(0) + + local d = function() + return a() + b() + end + + local count = -1 + + watch(function() + count += 1 + untrack(d) + c() + end) + + c(1) + CHECK(count == 1) + + a(1) + b(1) + CHECK(count == 1) + end +end) + TEST("events", function() local create = vide.create diff --git a/todo.md b/todo.md index 96e07f8..a82220c 100644 --- a/todo.md +++ b/todo.md @@ -8,7 +8,7 @@ - [x] onCleanup > `cleanup()` - [x] Index > `indexes()` - [x] For > `values()` - - [ ] untrack + - [x] untrack - [ ] batch - [ ] async/resource/loading/suspense - [ ] stores