Svelte绑定实体的Proxy数组无法修改的问题及优化咨询
Svelte可绑定属性修改不生效问题:Proxy数组无法添加元素
我在Svelte组件中通过属性派生变量:
let {entity = $bindable(), targetType}: { entity: EntityDTO, targetType: EntityType } = $props(); const links = $derived(entity.links?.filter(link => link.entityB.type === targetType) || []);
随后编写了向实体添加链接的函数:
function addLink(article: EntityDTO, link: EntityDTO): EntityDTO { const toReturn = addEntityLink(article, link, LinkType.REFER, LinkState.APPROVED); isFocused = false; return toReturn; }
其中addEntityLink是工具库函数,会在特定条件下向links属性push新链接:
console.log( "adding", newLink ); sourceEntity.links.push(newLink); console.log( "after adding", sourceEntity );
问题现象
执行push后日志显示链接并未被添加:
after adding { _id: 'entity1', links: [] }
检查发现links是Proxy(Array)类型,但工具代码不应感知这种数组不可变的情况。
无效尝试
尝试通过重新创建对象规避Proxy行为,但问题依旧:
function addLink(entity: EntityDTO, link: EntityDTO): EntityDTO { entity.links = [...(entity.links || [])] // 尝试规避Proxy行为 const toReturn = addEntityLink(entity, link, LinkType.REFER, LinkState.APPROVED); isFocused = false; entitySuggestions = filterAlreadyLinked(lastSuggestions, links); entity = toReturn; }
调试器中links仍为Proxy(Array)类型,日志依旧显示未添加链接。
异常日志
修改工具代码为以下形式后:
console.log( "adding", newLink, " to ", typeof sourceEntity.links); const links = [...sourceEntity.links, newLink]; sourceEntity.links = links; console.log( "links: ", links ); console.log( "after adding", sourceEntity );
输出异常日志:
links: [ { entityAType: undefined, entityAId: 'entity1', entityBType: undefined, entityBId: 'lib1', entityB: { _id: 'lib1', name: 'React Library', icon: 'react.png', categories: [Array], summary: 'A popular UI library' }, state: 'approved', type: 'refer' } ] after adding { _id: 'entity1', links: [] }
推测由于entity是可绑定属性,对其属性的修改未生效。
核心问题
- 如何在组件中隔离Proxy相关逻辑,避免样板代码降低可读性?
- 如何解决当前链接无法添加的问题?
重要说明
代码在浏览器中可正常运行,但测试用例失败:
it('adds a library to an article', async () => { // 创建可追踪的模拟实体对象 const testEntity = { _id: 'entity1', links: [] }; const { component } = render(EntityLinkSelector, { props: { entity: testEntity, targetType: EntityType.LIBRARY } }); const input = await screen.findByTestId('search-input'); // 1. 先聚焦输入框(对isFocused状态至关重要) await fireEvent.focus(input); await tick(); // 2. 输入内容(触发searchQuery更新) await fireEvent.input(input, { target: { value: 'react' } }); // 3. 等待防抖和请求完成 // await new Promise(resolve => setTimeout(resolve, 350)); await tick(); // 查找弹出框 const suggestionsPopover = await screen.findByTestId('suggestions-popover'); // 在弹出框内找到建议项 const suggestion = within(suggestionsPopover).getByText('React Library'); await fireEvent.click(suggestion); await tick(); // 验证建议项已从弹出框中移除 expect(within(suggestionsPopover).queryByText('React Library')).not.toBeInTheDocument(); // 验证链接已添加到相关链接区域 const relatedLinksSection = await screen.getByTestId('related-links'); expect(within(relatedLinksSection).getByText('React Library')).toBeInTheDocument(); })
内容的提问来源于stack exchange,提问作者Zied Hamdi
相关产品推荐
相关产品推荐

