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),
|
--- component?: (fun(component: u.renderer.FnComponent, tag: u.renderer.Tag): any),
|
||||||
--- unknown?: fun(tag: any): 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(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
|
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
|
else
|
||||||
return visitors.unknown and visitors.unknown(tree) or error 'unknown value: not a tag'
|
return visitors.unknown and visitors.unknown(tree) or error 'unknown value: not a tag'
|
||||||
end
|
end
|
||||||
end-- }}}
|
end -- }}}
|
||||||
|
|
||||||
--- @private
|
--- @private
|
||||||
--- @param tree u.renderer.Tree
|
--- @param tree u.renderer.Tree
|
||||||
@ -788,15 +788,15 @@ function Renderer:mount(tree) -- {{{
|
|||||||
or nil
|
or nil
|
||||||
if old_tree_kind == new_tree_kind then self.component_tree.ctx_by_node[old_tree] = nil end
|
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 ctx u.renderer.FnComponentContext
|
||||||
--- @param rendered_component u.renderer.Tree
|
--- @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
|
self.component_tree.ctx_by_node[new_tree] = ctx
|
||||||
-- The rendered component could have other components in its tree:
|
-- The rendered component could have other components in its tree:
|
||||||
-- recurse and simplify:
|
-- recurse and simplify:
|
||||||
local new_tree_simplified = H2.visit_tree(ctx.prev_tree, rendered_component)
|
local new_tree_simplified =
|
||||||
ctx.prev_tree = 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
|
return new_tree_simplified
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -804,13 +804,13 @@ function Renderer:mount(tree) -- {{{
|
|||||||
old_ctx.phase = 'update'
|
old_ctx.phase = 'update'
|
||||||
old_ctx.props = new_tag.attributes
|
old_ctx.props = new_tag.attributes
|
||||||
old_ctx.children = new_tag.children
|
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
|
else
|
||||||
local state = tracker.create_signal(nil)
|
local state = tracker.create_signal(nil)
|
||||||
|
|
||||||
--- @type u.renderer.FnComponentContext
|
--- @type u.renderer.FnComponentContext
|
||||||
local ctx = {
|
local ctx = {
|
||||||
phase = old_tree and 'update' or 'mount',
|
phase = 'mount',
|
||||||
props = new_tag.attributes,
|
props = new_tag.attributes,
|
||||||
children = new_tag.children,
|
children = new_tag.children,
|
||||||
state = state --[[@as any]],
|
state = state --[[@as any]],
|
||||||
@ -822,7 +822,7 @@ function Renderer:mount(tree) -- {{{
|
|||||||
-- first-renders to initialize the state without firing a
|
-- first-renders to initialize the state without firing a
|
||||||
-- re-render:
|
-- re-render:
|
||||||
ctx.unsubscribe = state:subscribe(render)
|
ctx.unsubscribe = state:subscribe(render)
|
||||||
return update_ctx_and_recurse(new_tree, ctx, rendered)
|
return update_ctx_and_recurse(ctx, rendered)
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
@ -836,29 +836,33 @@ function Renderer:mount(tree) -- {{{
|
|||||||
--- @param new_arr u.renderer.Node[]
|
--- @param new_arr u.renderer.Node[]
|
||||||
--- @return u.renderer.Node[]
|
--- @return u.renderer.Node[]
|
||||||
function H2.visit_array(old_arr, new_arr)
|
function H2.visit_array(old_arr, new_arr)
|
||||||
--- @type u.renderer.Node[]
|
|
||||||
local old_to_unmount = {}
|
|
||||||
--- @type table<any, u.renderer.Node>
|
--- @type table<any, u.renderer.Node>
|
||||||
local old_by_key = {}
|
local old_by_key = {}
|
||||||
for _, old in ipairs(old_arr or {}) do
|
|
||||||
local key = Renderer.tree_match(old, {
|
--- @param tree u.renderer.Tree
|
||||||
tag = function(t) return t.attributes.key end,
|
--- @param idx integer
|
||||||
component = function(_, t) return t.attributes.key end,
|
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
|
end
|
||||||
table.insert(old_to_unmount, old)
|
|
||||||
else
|
for idx, old in ipairs(old_arr or {}) do
|
||||||
old_by_key[key] = old
|
local key = get_or_set_key(old, idx)
|
||||||
end
|
if key then old_by_key[key] = old end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @type u.renderer.Node[]
|
--- @type u.renderer.Node[]
|
||||||
local resulting_nodes = {}
|
local resulting_nodes = {}
|
||||||
for _, new in ipairs(new_arr) do
|
for idx, new in ipairs(new_arr) do
|
||||||
local key = Renderer.tree_match(new, {
|
local key = get_or_set_key(new, idx)
|
||||||
tag = function(t) return t.attributes.key end,
|
|
||||||
component = function(_, t) return t.attributes.key end,
|
|
||||||
})
|
|
||||||
local old = nil
|
local old = nil
|
||||||
if key then
|
if key then
|
||||||
old = old_by_key[key]
|
old = old_by_key[key]
|
||||||
@ -867,10 +871,8 @@ function Renderer:mount(tree) -- {{{
|
|||||||
table.insert(resulting_nodes, H2.visit_tree(old, new))
|
table.insert(resulting_nodes, H2.visit_tree(old, new))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Unmount whatever is left in the "old" map:
|
||||||
for _, n in pairs(old_by_key) do
|
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)
|
H2.unmount(n)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user