feat: pass cleanup function to effect (#40)

This commit is contained in:
richard 2025-01-25 12:14:21 -08:00 • committed by GitHub
parent 6be2fbb746
commit 89f1dfeaa5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 35 additions and 11 deletions

View file

@ -9,9 +9,11 @@ type Cleanup = () -> ()
@param callback The function to run. @param callback The function to run.
@return A function that unsubscribes the callback. @return A function that unsubscribes the callback.
]=] ]=]
local function effect(callback: () -> Cleanup?): Cleanup local function effect(callback: (cleanup: Cleanup) -> Cleanup?): Cleanup
local dependencies, cleanup = store.capture(callback) local dependencies = {}
local cleanup: Cleanup?
local disconnected = false local disconnected = false
local disconnect
local function listener() local function listener()
if cleanup then if cleanup then
@ -19,16 +21,14 @@ local function effect(callback: () -> Cleanup?): Cleanup
end end
store.disconnect(dependencies, listener) store.disconnect(dependencies, listener)
dependencies, cleanup = store.capture(callback) dependencies, cleanup = store.capture(callback, disconnect)
if not disconnected then if not disconnected then
store.connect(dependencies, listener) store.connect(dependencies, listener)
end end
end end
store.connect(dependencies, listener) function disconnect()
return function()
if disconnected then if disconnected then
return return
end end
@ -40,6 +40,14 @@ local function effect(callback: () -> Cleanup?): Cleanup
cleanup() cleanup()
end end
end end
dependencies, cleanup = store.capture(callback, disconnect)
if not disconnected then
store.connect(dependencies, listener)
end
return disconnect
end end
return effect :: (callback: (() -> ()) | (() -> Cleanup)) -> Cleanup return effect :: (callback: ((cleanup: Cleanup) -> ()) | ((cleanup: Cleanup) -> Cleanup?)) -> Cleanup

View file

@ -133,9 +133,10 @@ end
@param callback The function to run. @param callback The function to run.
@return A tuple containing the captured atoms and the result of the function. @return A tuple containing the captured atoms and the result of the function.
]=] ]=]
local function capture<T>(callback: () -> T): (Set<Atom<any>>, T) local function capture<T, U...>(callback: (U...) -> T, ...: U...): (Set<Atom<any>>, T)
if listeners[callback] then -- If the callback is an atom, return it immediately
return { [callback] = true }, peek(callback) if listeners[callback :: any] then
return { [callback :: any] = true }, peek(callback)
end end
local dependencies: Set<Atom<any>> = {} local dependencies: Set<Atom<any>> = {}
@ -146,7 +147,7 @@ local function capture<T>(callback: () -> T): (Set<Atom<any>>, T)
local result = try(callback, function() local result = try(callback, function()
capturing.stack[capturing.index] = nil capturing.stack[capturing.index] = nil
capturing.index -= 1 capturing.index -= 1
end) end, ...)
return dependencies, result return dependencies, result
end end

View file

@ -93,4 +93,19 @@ return function()
a(2) a(2)
a(3) a(3)
end) end)
it("allows immediate self-cleanup", function()
local a = atom(1)
local cleanedUp = false
effect(function(cleanup)
assert(not cleanedUp, "cleanup ran twice")
cleanup()
cleanedUp = true
a()
end)
a(2)
a(3)
end)
end end