Computed Variables as seen in Weaver / Vue.js / Svelte / React

Untested, though in theory should work without issue.

The syntax / api is as should be and will not change in future additions/improvements.
This commit is contained in:
Sovereignty 2024-11-19 17:08:28 +00:00
commit b584fe0ba6

105
ModuleScripts/Computed.lua Normal file
View file

@ -0,0 +1,105 @@
local module = {}
local FF_COMPUTED_CONSTRUCTION_CALLBACK = false
local FF_COMPUTED_REFS = {}
local refValuesById = {}
function module.ref(value: any)
table.insert(refValuesById, { Value = value, OnSet = {} })
local id = #refValuesById
local ref = setmetatable({
Id = id,
get = function(self)
if FF_COMPUTED_CONSTRUCTION_CALLBACK then
table.insert(FF_COMPUTED_REFS, self.Id)
end;
return refValuesById[self.Id].Value;
end,
set = function(self, value: any)
self.Value = value
task.spawn(function()
local callbacks = refValuesById[self.Id].OnSet
for _, callback in callbacks do
callback(value)
end
end)
end,
}, {})
return ref
end
local computedsById = {}
function module.computed(computationCallback: () -> (any))
FF_COMPUTED_CONSTRUCTION_CALLBACK = true
table.insert(computedsById, { Value = computationCallback(), Callack = computationCallback, Refs = FF_COMPUTED_REFS, OnChange = {} })
local notifyChange = function(refId, compId)
return function()
local computedData: { Value: any, Callack: () -> any, OnChange: { } } = computedsById[refId]
local newComputedValue = computedData.Callack()
computedsById[compId].Value = newComputedValue
for _, callback in computedData.OnChange do
callback(newComputedValue)
end
end
end
local refs = FF_COMPUTED_REFS
if refs[1] then
for _, ref in refs do
table.insert(refValuesById[ref].OnSet, notifyChange(ref, #computedsById))
end
end
FF_COMPUTED_CONSTRUCTION_CALLBACK = false
FF_COMPUTED_REFS = {}
return setmetatable({ Value = computationCallback(), }, { Id = #computedsById, __index = function(self, key)
if key:upper() == "VALUE" then
return computedsById[#computedsById].Value
else
return rawget(self, key)
end
end})
end
function module.listenEvent(computed: typeof(setmetatable({ Id = 1}, {})), callback: (newValue: any) -> ())
table.insert(computedsById[computed.Id].OnChange, callback)
end
local Computed = module.computed
local Ref = module.ref
local ListenTo = module.listenEvent
local a = Ref(1)
local b = Ref(2)
local aAndB = Computed(function()
return a:get() * b:get()
end)
print(aAndB.Value) -- 2
ListenTo(aAndB, print)
a:set(2)
-- aAndB = 4
b:set(3)
-- aAndB = 6
return module