mirror of
https://github.com/littensy/charm.git
synced 2026-10-20 17:51:37 +00:00
feat!: run listen and subscribe callback in untracked
This commit is contained in:
parent
50afcaf6e9
commit
5c27052965
11 changed files with 28 additions and 156 deletions
|
|
@ -4,6 +4,6 @@ end
|
|||
|
||||
local Charm = require(script.Parent.Parent.charm.src)
|
||||
|
||||
export type Atom<T = any> = Charm.Atom<T>
|
||||
export type Atom<T> = Charm.Atom<T>
|
||||
|
||||
return Charm
|
||||
|
|
|
|||
|
|
@ -809,7 +809,7 @@ local function listen<T>(getter: Getter<T>, fn: (state: T, lastState: T?) -> ())
|
|||
return effect(function()
|
||||
local previous = current
|
||||
current = tracked()
|
||||
peek(fn, current, previous)
|
||||
untracked(fn, current, previous)
|
||||
end)
|
||||
end
|
||||
|
||||
|
|
@ -837,7 +837,7 @@ local function subscribe<T>(getter: Getter<T>, fn: (state: T, lastState: T) -> (
|
|||
if firstRun then
|
||||
firstRun = false
|
||||
else
|
||||
peek(fn, current, previous)
|
||||
untracked(fn, current, previous)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ local test = require("../../../tests/test")
|
|||
|
||||
local signal = Charm.signal
|
||||
local listen = Charm.listen
|
||||
local effect = Charm.effect
|
||||
|
||||
test("should listen to selector", function()
|
||||
local source, setSource = signal(0)
|
||||
|
|
@ -26,32 +25,23 @@ test("should listen to selector", function()
|
|||
assert(current == 2 and previous == 1, "should not run after unsub")
|
||||
end)
|
||||
|
||||
test("should run in peek", function()
|
||||
test("should run in untracked", function()
|
||||
local runs = 0
|
||||
local cleanups = 0
|
||||
local a, setA = signal(0)
|
||||
local b, setB = signal(0)
|
||||
|
||||
listen(a, function()
|
||||
runs += 1
|
||||
b()
|
||||
effect(function()
|
||||
return function()
|
||||
cleanups += 1
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
assert(runs == 1, "should run once on init")
|
||||
assert(cleanups == 0, "should not cleanup yet")
|
||||
|
||||
setA(1)
|
||||
assert(runs == 2, "should run on a change")
|
||||
assert(cleanups == 1, "should cleanup first call")
|
||||
|
||||
assert(runs == 2, "should run once on change")
|
||||
setB(1)
|
||||
assert(runs == 2, "should not run on b change")
|
||||
assert(cleanups == 1, "should not cleanup second call")
|
||||
setA(2)
|
||||
assert(runs == 3, "should run on a change")
|
||||
end)
|
||||
|
||||
test("should run if first value is nil", function()
|
||||
|
|
@ -67,36 +57,6 @@ test("should run if first value is nil", function()
|
|||
assert(runs == 2, "should run once on change")
|
||||
end)
|
||||
|
||||
test("should track inner subs", function()
|
||||
local order = {}
|
||||
local a, setA = signal(1)
|
||||
|
||||
local unsub = listen(a, function()
|
||||
table.insert(order, 1)
|
||||
listen(a, function()
|
||||
table.insert(order, 2)
|
||||
end)
|
||||
listen(a, function()
|
||||
table.insert(order, 3)
|
||||
end)
|
||||
end)
|
||||
|
||||
assert(table.concat(order) == "123", `bad mount order: {table.concat(order)}`)
|
||||
|
||||
table.clear(order)
|
||||
setA(a() + 1)
|
||||
assert(table.concat(order) == "123", `bad order: {table.concat(order)}`)
|
||||
|
||||
table.clear(order)
|
||||
setA(a() + 1)
|
||||
assert(table.concat(order) == "123", `bad order: {table.concat(order)}`)
|
||||
|
||||
table.clear(order)
|
||||
unsub()
|
||||
setA(a() + 1)
|
||||
assert(table.concat(order) == "", `bad order: {table.concat(order)}`)
|
||||
end)
|
||||
|
||||
test("should skip redundant updates", function()
|
||||
local order = {}
|
||||
local a, setA = signal(0)
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@ local test = require("../../../tests/test")
|
|||
local signal = Charm.signal
|
||||
local computed = Charm.computed
|
||||
local subscribe = Charm.subscribe
|
||||
local listen = Charm.listen
|
||||
local effect = Charm.effect
|
||||
|
||||
test("should subscribe to selector", function()
|
||||
local source, setSource = signal(0)
|
||||
|
|
@ -28,36 +26,23 @@ test("should subscribe to selector", function()
|
|||
assert(current == 2 and previous == 1, "should not run after unsub")
|
||||
end)
|
||||
|
||||
test("should run in peek", function()
|
||||
test("should run in untracked", function()
|
||||
local runs = 0
|
||||
local cleanups = 0
|
||||
local a, setA = signal(0)
|
||||
local b, setB = signal(0)
|
||||
|
||||
subscribe(a, function()
|
||||
runs += 1
|
||||
b()
|
||||
effect(function()
|
||||
return function()
|
||||
cleanups += 1
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
assert(runs == 0, "should not run once on init")
|
||||
assert(cleanups == 0, "should not cleanup yet")
|
||||
|
||||
setA(1)
|
||||
assert(runs == 1, "should run once on change")
|
||||
assert(cleanups == 0, "should not cleanup yet")
|
||||
|
||||
setB(1)
|
||||
assert(runs == 1, "should not run on b change")
|
||||
assert(cleanups == 0, "should not cleanup first call")
|
||||
|
||||
setA(2)
|
||||
assert(runs == 2, "should run on a change")
|
||||
assert(cleanups == 1, "should cleanup first call")
|
||||
end)
|
||||
|
||||
test("should ensure correct execution order", function()
|
||||
|
|
@ -86,33 +71,6 @@ test("should ensure correct execution order", function()
|
|||
assert(table.concat(order) == "123", `bad order: {table.concat(order)}`)
|
||||
end)
|
||||
|
||||
test("should track inner subs", function()
|
||||
local order = {}
|
||||
local a, setA = signal(1)
|
||||
|
||||
local unsub = subscribe(a, function()
|
||||
table.insert(order, 1)
|
||||
listen(a, function()
|
||||
table.insert(order, 2)
|
||||
end)
|
||||
listen(a, function()
|
||||
table.insert(order, 3)
|
||||
end)
|
||||
end)
|
||||
|
||||
setA(a() + 1)
|
||||
assert(table.concat(order) == "123", `bad order: {table.concat(order)}`)
|
||||
|
||||
table.clear(order)
|
||||
setA(a() + 1)
|
||||
assert(table.concat(order) == "123", `bad order: {table.concat(order)}`)
|
||||
|
||||
table.clear(order)
|
||||
unsub()
|
||||
setA(a() + 1)
|
||||
assert(table.concat(order) == "", `bad order: {table.concat(order)}`)
|
||||
end)
|
||||
|
||||
test("should skip redundant updates", function()
|
||||
local order = {}
|
||||
local a, setA = signal(0)
|
||||
|
|
|
|||
|
|
@ -2,8 +2,4 @@ if not script then
|
|||
return require("../charm/src")
|
||||
end
|
||||
|
||||
local Charm = require(script.Parent.Parent.charm.src)
|
||||
|
||||
export type Atom<T = any> = Charm.Atom<T>
|
||||
|
||||
return Charm
|
||||
return require(script.Parent.Parent.charm.src)
|
||||
|
|
|
|||
|
|
@ -1,5 +1 @@
|
|||
local Charm = require(script.Parent.Parent.charm.src)
|
||||
|
||||
export type Atom<T = any> = Charm.Atom<T>
|
||||
|
||||
return Charm
|
||||
return require(script.Parent.Parent.charm.src)
|
||||
|
|
|
|||
|
|
@ -1,12 +1 @@
|
|||
type CoreReactBinding<T> = {
|
||||
getValue: (self: CoreReactBinding<T>) -> T,
|
||||
_source: string?,
|
||||
}
|
||||
|
||||
type ReactBindingMap = {
|
||||
map: <T, U>(self: CoreReactBinding<T> & ReactBindingMap, (T) -> U) -> ReactBindingMap & CoreReactBinding<U>,
|
||||
}
|
||||
|
||||
export type Binding<T> = CoreReactBinding<T> & ReactBindingMap
|
||||
|
||||
return require(script.Parent.Parent.Parent:WaitForChild("@rbxts-js").React)
|
||||
|
|
|
|||
|
|
@ -17,10 +17,7 @@ local function useSignalState<T>(getter: () -> T, dependencies: { any }?): T
|
|||
local value, setValue = React.useState(getter)
|
||||
|
||||
React.useLayoutEffect(function()
|
||||
return Charm.effect(function()
|
||||
-- Wrap in untracked to avoid tracking inner effect and atom calls
|
||||
Charm.untracked(setValue, getter())
|
||||
end)
|
||||
return Charm.listen(getter, setValue)
|
||||
end, dependencies or {})
|
||||
|
||||
return value
|
||||
|
|
@ -42,10 +39,7 @@ local function useSignalBinding<T>(getter: () -> T, dependencies: { any }?)
|
|||
local binding, setBinding = React.useBinding(initialValue)
|
||||
|
||||
React.useLayoutEffect(function()
|
||||
return Charm.effect(function()
|
||||
-- Wrap in untracked to avoid tracking inner effect and atom calls
|
||||
Charm.untracked(setBinding, getter())
|
||||
end)
|
||||
return Charm.listen(getter, setBinding)
|
||||
end, dependencies or {})
|
||||
|
||||
return binding
|
||||
|
|
|
|||
|
|
@ -1,5 +1 @@
|
|||
local Charm = require(script.Parent.Parent.charm.src)
|
||||
|
||||
export type Atom<T = any> = Charm.Atom<T>
|
||||
|
||||
return Charm
|
||||
return require(script.Parent.Parent.charm.src)
|
||||
|
|
|
|||
|
|
@ -11,10 +11,7 @@ local Vide = require("./Vide")
|
|||
local function useSignalState<State>(getter: () -> State): () -> State
|
||||
local state = Vide.source(getter())
|
||||
|
||||
Vide.cleanup(Charm.effect(function()
|
||||
-- Wrap in untracked to avoid tracking inner effect and atom calls
|
||||
Charm.untracked(state :: (State) -> State, getter())
|
||||
end))
|
||||
Vide.cleanup(Charm.listen(getter, state))
|
||||
|
||||
return state
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue