javascript - 更新 ngrx/store 中的对象

标签 javascript angular typescript rxjs ngrx

我正在为 Angular 2 应用程序使用 @ngrx/store。

我的商店拥有一个列表,比如 Book 对象。我想更新其中一个对象中的字段。我也碰巧有一个要更新的 Book 实例的 Observable(比如,selectedBook)。

为了进行更新,我打算使用 UpdateBookAction 和新书的有效负载调用 reducer。因此,我通过订阅 selectedBook 然后调用 Object.assign() 对现有 Book 对象进行了深度复制。

但是当我尝试写入副本的其中一个字段时,出现以下错误。 (这恰好与我尝试直接写入商店中的 Book 对象时遇到的错误相同。)

错误

Cannot assign to read only property 'name' of object '#<Object>' at ViewWrappedError.BaseError [as constructor]

代码

ngOnInit() {
    this.book$ = this.store.let(fromRoot.getSelectedBook);
    //...
}

someFunction() {
    //...
    this.book$.subscribe(book => {

        let updatedBook = Object.assign({}, book);
        updatedBook.name = 'something else';          // <--- THIS IS WHAT THROWS

        let action = new BookUpdateAction(updatedBook);
        this.store.dispatch(action);

    }
}

评论后澄清

我假设我可以使用不是商店的整个状态的有效负载执行操作。 (事实上​​这似乎是必要的,不是吗?)鉴于文档,我相信情况就是如此。

我想要采取的行动是这样的:

Action = UPDATE, payload = {'id': 1234, 'name': 'something new'}

如前所述,我打算这样调用:

this.store.dispatch(action);

大概在幕后,ngrx 将我的操作连同(不可变的)当前状态一起传递给 reducer。

所以从那里开始,一切都应该正常工作。我在 reducer 中的逻辑不会改变现有状态,它只是根据现有状态和我传入的有效负载创建一个新状态。

这里真正的问题是我如何合理地构建新的“objectToUpdate”,以便我可以将其作为有效负载传递。

我可以这样做:

this.book$.subscribe(book => {

    let updatedBook = new Book();
    updatedBook.id = book.id;
    //set all other fields manually...
    updatedBook.name = 'something else';

    let action = new BookUpdateAction(updatedBook);
    this.store.dispatch(action);

}

但我们不只是在这里谈论两个领域……如果我的书有多个领域怎么办?我是否必须每次都从头开始手动构建一本新书来更新一个字段?

我的解决方案是使用 Object.assign({}, book) 进行深度复制(而不是改变旧的!),然后仅更新我正在查找的字段触摸。

最佳答案

ngrx store 的想法是只有一个真实的地方,这意味着所有对象都是不可变的,改变任何东西的唯一方法是将所有东西作为一个整体重新创建。此外,您可能正在使用 ngrx freeze ( https://github.com/codewareio/ngrx-store-freeze ),这意味着所有对象都将以只读方式创建,因此您将无法更改任何对象(如果您想完全遵循 redux 模式,这有利于开发).如果您删除商店卡住对象的部分,您将能够更改它,但这不是最佳实践。

我建议您执行以下操作:使用带异步管道的 ngrx observable 将数据(在您的案例书中)放入只能获取输入和输出某些事件的dumb组件中。然后,在dumb组件内部,您可以通过复制该对象来“编辑”该对象,完成后,您可以将更改发回订阅商店的智能组件,并允许它更改状态通过商店(提交)。这种方式是最好的,因为为了一个非常小的变化而改变整个状态并不是很常见(比如双向绑定(bind),当用户输入时......)。

如果您遵循 redux 模式,那么您将能够添加历史记录,这意味着商店将保留最近 X 状态重新创建的副本,因此您可以获得撤消功能、更易于调试、时间线等

您的问题是您直接编辑属性而不是重新创建整个状态。

关于javascript - 更新 ngrx/store 中的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40899859/

相关文章:

javascript - 对 TinySong 的 JSONP 请求总是失败

javascript - 如何在委托(delegate)的事件监听器中支持 stopPropagation

javascript - 提交表单时单击了提交按钮

angular - 带 Angular 的雪袋?

javascript - Angular Material 对话框 - AGM 贴图

javascript - 选择框 Laravel 选择 onChange

angular - 如何从我的组件内容中将 columnDefinitions 添加到 md-table

JavaScript 监听器 - Angular 2 区域

node.js - 如何在 Visual Studio Code (VS Code) 上调试用 Typescript 编写的 Express 应用程序

angular - 为什么 console.log 在我记录 string + object 时记录不同的结果