fix: avoid reconnecting to dependencies after cleanup (#14)

* fix: cancel reconnection when unsubscribing

* test: remove print

* feat: allow factory to return nil

* perf: use `next` iteration
This commit is contained in:
richard 2024-07-10 15:13:36 -07:00 • committed by GitHub
parent 62be3e496d
commit c6762a6525
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 87 additions and 63 deletions

View file

@ -2,6 +2,8 @@ local effect = require(script.Parent.effect)
local types = require(script.Parent.types)
type Molecule<T> = types.Molecule<T>
local function noop() end
--[=[
Creates an instance of `factory` for each item in the atom's state, and
cleans up the instance when the item is removed. Returns a cleanup function
@ -11,34 +13,38 @@ type Molecule<T> = types.Molecule<T>
@param factory The function that tracks the lifecycle of each item.
@return A function that unsubscribes all instances.
]=]
local function observe<K, V>(molecule: Molecule<{ [K]: V }>, factory: (value: V, key: K) -> () -> ()): () -> ()
local function observe<K, V>(molecule: Molecule<{ [K]: V }>, factory: (value: V, key: K) -> (() -> ())?): () -> ()
local connections: { [K]: () -> () } = {}
local unsubscribe = effect(function()
local state = molecule()
for key, disconnect in connections do
for key, disconnect in next, connections do
if state[key] == nil then
connections[key] = nil
disconnect()
end
end
for key, value in state do
for key, value in next, state do
if not connections[key] then
connections[key] = factory(value, key)
connections[key] = factory(value, key) or noop
end
end
end)
local function cleanup()
unsubscribe()
for _, disconnect in connections do
for _, disconnect in next, connections do
disconnect()
end
table.clear(connections)
end
return cleanup
end
return observe
return observe :: <K, V>(
molecule: Molecule<{ [K]: V }>,
factory: ((value: V, key: K) -> () -> ()) | (value: V, key: K) -> ()
) -> () -> ()