Working better now (but see notes)
Some checks failed
NeoVim tests / code-quality (push) Failing after 1m18s
Some checks failed
NeoVim tests / code-quality (push) Failing after 1m18s
Even so, some things can get screwy if the component tree sets suspicious `key`s. Like: ```lua { 'String 1', -- auto-assigned key = idx(1) h(Component, { key = 1 }, {}), -- conflicting key(1) 'String 2', -- auto-assigned key = idx(3) h(Component, { key = 2 }, {}), -- key = 2 } ``` In this example, there are two elements competing for key `1`, which causes weird render issues.
This commit is contained in:
parent
8fa2784bf7
commit
fdb2a49638
@ -86,7 +86,7 @@ M.Renderer = Renderer
|
||||
--- component?: (fun(component: u.renderer.FnComponent, tag: u.renderer.Tag): any),
|
||||
--- unknown?: fun(tag: any): any
|
||||
--- }
|
||||
function Renderer.tree_match(tree, visitors)-- {{{
|
||||
function Renderer.tree_match(tree, visitors) -- {{{
|
||||
local function is_tag(x) return type(x) == 'table' and x.kind == 'tag' end
|
||||
local function is_tag_arr(x) return type(x) == 'table' and not is_tag(x) end
|
||||
|
||||
@ -108,7 +108,7 @@ function Renderer.tree_match(tree, visitors)-- {{{
|
||||
else
|
||||
return visitors.unknown and visitors.unknown(tree) or error 'unknown value: not a tag'
|
||||
end
|
||||
end-- }}}
|
||||
end -- }}}
|
||||
|
||||
--- @private
|
||||
--- @param tree u.renderer.Tree
|
||||
@ -788,15 +788,15 @@ function Renderer:mount(tree) -- {{{
|
||||
or nil
|
||||
if old_tree_kind == new_tree_kind then self.component_tree.ctx_by_node[old_tree] = nil end
|
||||
|
||||
--- @param new_tree u.renderer.Tree
|
||||
--- @param ctx u.renderer.FnComponentContext
|
||||
--- @param rendered_component u.renderer.Tree
|
||||
local function update_ctx_and_recurse(new_tree, ctx, rendered_component)
|
||||
local function update_ctx_and_recurse(ctx, rendered_component)
|
||||
self.component_tree.ctx_by_node[new_tree] = ctx
|
||||
-- The rendered component could have other components in its tree:
|
||||
-- recurse and simplify:
|
||||
local new_tree_simplified = H2.visit_tree(ctx.prev_tree, rendered_component)
|
||||
ctx.prev_tree = new_tree_simplified
|
||||
local new_tree_simplified =
|
||||
M.h('text', ctx.props, H2.visit_tree(ctx.prev_tree, rendered_component))
|
||||
ctx.prev_tree = rendered_component
|
||||
return new_tree_simplified
|
||||
end
|
||||
|
||||
@ -804,13 +804,13 @@ function Renderer:mount(tree) -- {{{
|
||||
old_ctx.phase = 'update'
|
||||
old_ctx.props = new_tag.attributes
|
||||
old_ctx.children = new_tag.children
|
||||
return update_ctx_and_recurse(new_tree, old_ctx, NewC(old_ctx))
|
||||
return update_ctx_and_recurse(old_ctx, NewC(old_ctx))
|
||||
else
|
||||
local state = tracker.create_signal(nil)
|
||||
|
||||
--- @type u.renderer.FnComponentContext
|
||||
local ctx = {
|
||||
phase = old_tree and 'update' or 'mount',
|
||||
phase = 'mount',
|
||||
props = new_tag.attributes,
|
||||
children = new_tag.children,
|
||||
state = state --[[@as any]],
|
||||
@ -822,7 +822,7 @@ function Renderer:mount(tree) -- {{{
|
||||
-- first-renders to initialize the state without firing a
|
||||
-- re-render:
|
||||
ctx.unsubscribe = state:subscribe(render)
|
||||
return update_ctx_and_recurse(new_tree, ctx, rendered)
|
||||
return update_ctx_and_recurse(ctx, rendered)
|
||||
end
|
||||
end,
|
||||
})
|
||||
@ -836,29 +836,33 @@ function Renderer:mount(tree) -- {{{
|
||||
--- @param new_arr u.renderer.Node[]
|
||||
--- @return u.renderer.Node[]
|
||||
function H2.visit_array(old_arr, new_arr)
|
||||
--- @type u.renderer.Node[]
|
||||
local old_to_unmount = {}
|
||||
--- @type table<any, u.renderer.Node>
|
||||
local old_by_key = {}
|
||||
for _, old in ipairs(old_arr or {}) do
|
||||
local key = Renderer.tree_match(old, {
|
||||
tag = function(t) return t.attributes.key end,
|
||||
component = function(_, t) return t.attributes.key end,
|
||||
|
||||
--- @param tree u.renderer.Tree
|
||||
--- @param idx integer
|
||||
local function get_or_set_key(tree, idx)
|
||||
return Renderer.tree_match(tree, {
|
||||
tag = function(t)
|
||||
if not t.attributes.key then t.attributes.key = idx end
|
||||
return t.attributes.key
|
||||
end,
|
||||
component = function(_, t)
|
||||
if not t.attributes.key then t.attributes.key = idx end
|
||||
return t.attributes.key
|
||||
end,
|
||||
})
|
||||
if not key then
|
||||
table.insert(old_to_unmount, old)
|
||||
else
|
||||
old_by_key[key] = old
|
||||
end
|
||||
end
|
||||
|
||||
for idx, old in ipairs(old_arr or {}) do
|
||||
local key = get_or_set_key(old, idx)
|
||||
if key then old_by_key[key] = old end
|
||||
end
|
||||
|
||||
--- @type u.renderer.Node[]
|
||||
local resulting_nodes = {}
|
||||
for _, new in ipairs(new_arr) do
|
||||
local key = Renderer.tree_match(new, {
|
||||
tag = function(t) return t.attributes.key end,
|
||||
component = function(_, t) return t.attributes.key end,
|
||||
})
|
||||
for idx, new in ipairs(new_arr) do
|
||||
local key = get_or_set_key(new, idx)
|
||||
local old = nil
|
||||
if key then
|
||||
old = old_by_key[key]
|
||||
@ -867,10 +871,8 @@ function Renderer:mount(tree) -- {{{
|
||||
table.insert(resulting_nodes, H2.visit_tree(old, new))
|
||||
end
|
||||
|
||||
-- Unmount whatever is left in the "old" map:
|
||||
for _, n in pairs(old_by_key) do
|
||||
table.insert(old_to_unmount, n)
|
||||
end
|
||||
for _, n in pairs(old_to_unmount) do
|
||||
H2.unmount(n)
|
||||
end
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user