Search code examples
angulartypescriptrxjsngrxangular11

Best practice for getting an immutable item to edit in a component from an RXJS/NGRX store in Angular


This week we've upgraded our Angular v9 app to v11 and RXJS v6.6. For the most part this has gone really smoothly but because the store is now in freeze mode we're getting a few errors where the code was previously updating the store.

Whilst most of this has been in helper methods we use to update the store in the reducers (and easily refactorable) one common approach we were using in our edit components is causing issues.

We generally do the following in a component that is used to edit a complete model/item:

  • Get item from the store using RXJS operators e.g. filter, map etc
  • Set it to a property on the component inside a subscribe (as you can't edit an observable object)
  • Try to edit via ngModel in the view or other code inside the component

This then results in "Cannot assign to read only property..." errors. In most cases creating a shallow copy by using a spread or Object.assign() works but for our more complicated objects this doesn't as we need a deep copy.

Is there a better/proper way to get an item from an RXJS/NGRX store to edit without then having to use custom code to create a deep copy of it in the component? At the moment we're getting around the issue with JSON.parse(JSON.stringify(Object)) but it just doesn't feel right!


Solution

  • This may not answer your question but hopefully it will shed some light for you.

    Imagine you subscribe to an object to your store and you modify a property of that object, you will actually change the property in the store and locally because objects and arrays are reference types. The only way you should change the properties in the store is through actions and the updates should happen immutably within the reducer to enable time travel debugging.

    This link should help explain it a bit more.

    As for as techniques to create copies, I think like you mentioned Object.assign and JSON.parse(JSON.stringify(Object)) seem okay.

    Other ways are to spread an array [...array] to create a copy and to spread an object to create a copy { ...object }.