Merge pull request #72 from thesabinelim/effects

Effects and Derived Values
This commit is contained in:
Robert Jelic
2023-05-13 19:29:04 +02:00
committed by GitHub

View File

@@ -167,27 +167,64 @@ local function registerFunctionEvent(self, data, event, renderContext)
end end
end end
local potentialObservers = {} local effectStack = {}
local clearEffectDependencies = function(effect)
for _, dependency in ipairs(effect.dependencies) do
for index, backlink in ipairs(dependency) do
if (backlink == effect) then
table.remove(dependency, index)
end
end
end
effect.dependencies = {};
end
return { return {
basalt = function() basalt = function(basalt)
local object = { local object = {
reactive = function(initialValue) reactive = function(initialValue)
local internalValue = initialValue local value = initialValue
local observers = {} local observerEffects = {}
local getter = function() local getter = function()
if (potentialObservers ~= nil) then local invokingEffect = effectStack[#effectStack]
table.insert(observers, potentialObservers[#potentialObservers]) if (invokingEffect ~= nil) then
table.insert(observerEffects, invokingEffect)
table.insert(invokingEffect.dependencies, observerEffects)
end end
return internalValue return value
end end
local setter = function(value) local setter = function(newValue)
internalValue = value value = newValue
for _, updateFn in ipairs(observers) do local observerEffectsCopy = {}
updateFn(internalValue) for index, effect in ipairs(observerEffects) do
observerEffectsCopy[index] = effect
end
for _, effect in ipairs(observerEffectsCopy) do
effect.execute()
end end
end end
return getter, setter return getter, setter
end,
effect = function(effectFn)
local effect = {dependencies = {}}
local execute = function()
clearEffectDependencies(effect)
table.insert(effectStack, effect)
effectFn()
table.remove(effectStack)
end
effect.execute = execute
effect.execute()
end,
derived = function(computeFn)
local getValue, setValue = basalt.reactive();
basalt.effect(function()
setValue(computeFn())
end)
return getValue;
end end
} }
return object return object
@@ -231,9 +268,7 @@ return {
local value = load("return " .. expression, nil, "t", renderContext.env)() local value = load("return " .. expression, nil, "t", renderContext.env)()
self:updateValue(prop, value) self:updateValue(prop, value)
end end
table.insert(potentialObservers, update) basalt.effect(update)
update()
table.remove(potentialObservers)
end end
self:updateSpecifiedValuesByXMLData(data, { self:updateSpecifiedValuesByXMLData(data, {
@@ -345,7 +380,6 @@ return {
loadLayout = function(self, path, props) loadLayout = function(self, path, props)
if(fs.exists(path))then if(fs.exists(path))then
local renderContext = {} local renderContext = {}
renderContext.potentialObservers = {}
renderContext.env = _ENV renderContext.env = _ENV
renderContext.env.props = props renderContext.env.props = props
local f = fs.open(path, "r") local f = fs.open(path, "r")
@@ -475,6 +509,7 @@ return {
Button = function(base, basalt) Button = function(base, basalt)
local object = { local object = {
updateValue = function(self, name, value) updateValue = function(self, name, value)
basalt.log("Updating value, " .. name .. " = " .. value)
if (value == nil) then return end if (value == nil) then return end
base.updateValue(self, name, value) base.updateValue(self, name, value)
if (name == "text") then if (name == "text") then