@ngrx 在递归使用智能组件时从存储中选择特定的状态片
Posted
技术标签:
【中文标题】@ngrx 在递归使用智能组件时从存储中选择特定的状态片【英文标题】:@ngrx select specific slice of state from store when using a smart component recursively 【发布时间】:2018-06-16 00:22:54 【问题描述】:我是ngrx
的新手,遇到了这个小问题,我还没有弄清楚如何解决。
基本上我有一个ListComponent
,它从ngrx
存储中呈现ListItemComponent
s 的数组。
@Component(
...
template: `
<list-item *ngFor="let item of item$ | async" [data]="item">
</list-item>
`
)
export class ListComponent implements OnInit
item$: Observable<ListItem>;
constructor(private store: Store<ListState>)
ngOnInit()
this.item$ = this.store.select(selectListItems);
现在,在ListItemComponent
内部,在某些特定情况下,我想渲染另一个ListComponent
,我可以在其中添加项目,但这不起作用,因为我收到Maximum call stack size exceeded
错误。
我的猜测是,如果我错了,请纠正我,因为嵌套的 ListComponent
正在访问与根 ListComponent
相同的状态片段,它只是试图一遍又一遍地嵌套和呈现相同的列表再次进入无限。
那么问题来了,我应该如何组合我的选择器以便在状态树中为每个嵌套的ListComponent
提供正确的入口点?
编辑
这是一个working stackblitz project,现在我的应用程序中在ListItem
内呈现List
的逻辑不同,但问题是相同的。
【问题讨论】:
你只需要在ListComponent
中将selectListItems
作为Input
传递
想详细说明这将如何解决我的问题?我的意思是,为了将函数作为输入传递,我应该让我的ListStepComponent
商店也知道吗?
你能把selectListItems
和ListStepComponent
的代码贴出来吗?
是的,给我一些时间来重现 stackblitz 中的示例
1 使用应用程序组件控制数据 - 智能组件,2 将项目分配为 @Input,3. 将状态更改为树结构,如 items:[name:'item1',items:[] ,name:'item2',items:[]]
【参考方案1】:
我认为你是对的:
我的猜测是,如果我错了,请纠正我,因为嵌套的 ListComponent 正在访问与根 ListComponent 相同的状态片,它只是试图一遍又一遍地嵌套和渲染相同的列表到无穷大.
尝试更新ListComponent
以接受ListItemComponent
的组件输入变量。请参阅工作示例https://stackblitz.com/edit/angular-ngrx-recursive-components-7mzncj
在该示例中,第 5 个ListItemComponent
也呈现ListComponent
。但是,当单击第 5 个 ListItemComponent 上的“将元素添加到列表”按钮时,代码仍在将新元素添加到父列表中。我猜你会想要更新你的处理逻辑。不确定您要完成什么。
核心问题是列表是自己生成的。因此,如果一个列表生成另一个列表,则会遇到递归问题。通过使用组件输入变量,您可以阻止列表自行生成并消除递归问题。
更新:
我自己来了这个答案,但我只是注意到@FanCheung,在 cmets 中,之前提出了基本上这个解决方案。
【讨论】:
是的,在阅读@FanCheung 评论后,我基本上得出了与您提供的相同的解决方案。现在的问题是在相应的子列表中添加新生成的列表项。我想我应该更新reducer以遍历整个树,从调度动作的地方找到正确的节点(也许有一些唯一的ID?)并返回状态......我看到这种方法的问题是,因为选择器正在选择根列表,每当我添加嵌套步骤时,它都会更新整个状态树,而我希望选择器只影响相应的分支 @OsmanCea 实际上我认为您不必担心更新整个状态树(至少在性能方面)。如果你推出一个新的状态树,但它只有一点点改变,我认为 Angular 足够聪明,可以只更新那些实际改变的 DOM 片段。是的,从角度来看差异会有一些开销,但我认为它可以忽略不计(除非你的列表真的很大,我想)。 例如,如果您在商店中订阅了一个列表,然后在列表中附加了一些内容,您的订阅将收到一份全新的列表副本。 Angular 足够聪明,only 实际上在最后添加了新项目。如果您的列表项都由它们自己的组件呈现,您可以在ngOnChanges
期间通过console.log
进行测试。当您将某些内容添加到列表时,您会注意到现有列表元素不会运行它们的OnChanges
。唯一的区别是添加一个新元素。 Angular 非常聪明 :)
因为没有人愿意给我一个答案,所以你得到了赏金;)
我确实解决了我的问题(这意味着为每个列表组件生成一些唯一的 id,获取给定 id 的路径,并做一些深度状态更新不可变的东西,但是嘿,这是值得的) 以上是关于@ngrx 在递归使用智能组件时从存储中选择特定的状态片的主要内容,如果未能解决你的问题,请参考以下文章
在 angular/ngrx 应用程序中将状态保存到本地存储的逻辑的位置