allow init/getState injection into StatefulElement

This commit is contained in:
PeaAshMeter 2026-06-04 22:07:03 +03:00
parent fdff65d94d
commit cfe8f83087
3 changed files with 22 additions and 9 deletions

View File

@ -34,6 +34,20 @@ function builder:makeKey(element)
return element.type .. "<" .. tostring(element.key) .. ">" return element.type .. "<" .. tostring(element.key) .. ">"
end end
--- @generic T
--- @param element StatefulElement<T>
--- @return T
function builder:initStateOf(element)
return element.initState and element:initState() or {}
end
--- @generic T
--- @param element StatefulElement<T>
--- @return T
function builder:getStateOf(element)
return element.getState and element:getState() or self.states[self:makeKey(element)]
end
--- @param cur UIElement --- @param cur UIElement
--- @private --- @private
function builder:build_step(cur) function builder:build_step(cur)
@ -43,9 +57,9 @@ function builder:build_step(cur)
local key = self:makeKey(cur) local key = self:makeKey(cur)
if key then if key then
cur = cur --[[@as StatefulElement]] cur = cur --[[@as StatefulElement]]
local storedState = self.states[key] local storedState = self:getStateOf(cur)
if not storedState then if not storedState then
self.states[key] = cur.state self.states[key] = self:initStateOf(cur)
else else
cur.state = storedState cur.state = storedState
end end

View File

@ -2,14 +2,15 @@ local SingleChildElement = require "lib.simple_ui.core.single_child_element"
--- @generic T : table --- @generic T : table
--- @class StatefulElement<T> : SingleChildElement --- @class StatefulElement<T> : SingleChildElement
--- @field state T --- @field initState? fun(self: StatefulElement<T>): T Создает исходное состояние элемента, когда он попадает в дерево в первый раз.
--- @field getState? fun(self: StatefulElement<T>): T Возвращает состояние элемента. Можно переопределить, чтобы хранить его где хочется.
local element = setmetatable({}, SingleChildElement) local element = setmetatable({}, SingleChildElement)
element.__index = element element.__index = element
element.type = "StatefulElement" element.type = "StatefulElement"
element.state = {} element.state = {}
--- @return StatefulElement<T> --- @return StatefulElement<T>
--- @param values {key: any, state: T?, child: UIElement?} --- @param values {key: any, child: UIElement?}
function element:new(values) function element:new(values)
return SingleChildElement.new(self, values) return SingleChildElement.new(self, values)
end end

View File

@ -16,8 +16,9 @@ local Canary = setmetatable({}, StatefulElement)
Canary.__index = Canary Canary.__index = Canary
Canary.type = "Canary" Canary.type = "Canary"
--- @class CanaryState function Canary:initState()
Canary.state = { i = 0 } return { i = self.key == "canary1" and 0 or 100 }
end
function Canary:build() function Canary:build()
self.state.i = self.state.i and self.state.i + 1 or 0 self.state.i = self.state.i and self.state.i + 1 or 0
@ -62,9 +63,6 @@ function MyWidget:build()
height = 100, height = 100,
child = Canary:new { child = Canary:new {
key = "canary2", key = "canary2",
state = {
i = 100
}
} }
}, },
}, },