Simplify NGRX Signal Store advanced patchState usecases with Immer immutable utility

Tomasz Ducin
InstructorTomasz Ducin
Share this video with your friends

Social Share Links

Send Tweet
Published 2 months ago
Updated 2 weeks ago

In this lesson, you’ll learn how to manage nested state updates efficiently using patchState, and Immer’s produce function to ensure immutability.

The produce function in Immer takes the current state and a function that modifies a draft of that state. After the modifications, produce returns a new, immutable state object that incorporates the changes made to the draft.

Check out the ngrx-immer package!

[00:00] Let's also add a similar way to update the salary filters, so that would be updates salary from and updates salary to. I'm going to copy function later on when we've got one defined. So const new value is going to be since salary is a number we're going to [00:20] parse the integer from whatever we get from the dom. So here we would simply get the value of the HTML input element. And we would define a function where we have this dot store. And let's say, the function, the method that we'll define in just a moment is going to be called [00:40] update filters salary, just to make things simple. And we want to have one method that would update both the from and the to. So we would pass that. In this case, we are updating the from. So that would be basically from, and here comes the new value. And accordingly, we would have [01:00] another method that would do the very same thing, and that would be update salary to. Okay. We've got the salary from and the salary 2. So we would also create accordingly the inputs. So let's quickly add input type equals. Here comes the number since we want to use [01:20] the features of the HTML Impost. Let's say that we're going to increase by 1,000, and there would be a place holder, which is salary from and salary to. Now we're going to synchronize the values in a very similar manner. So the value is going to be accessed [01:39] directly from the store. Of course, there could be a method on the component level that capsulate this, but we don't need it. So store dot filters dot salary. And since this is salary from, let's just put the from 1 and invoke it. And, of course, we also need to synchronize it the other way [01:59] around. So here we would have the method that we have just created, which is the update salary from and update salary to. So in this case, this is update salary from, and let's just pass the event. And similar, we would have the salary too. So [02:19] type number step 1,000 salary 2, store filters salary 2, and update salary 2. So this is the dump, the HTML part, and what we are missing is the definition of the method. So let's now walk back to the employee store definition. So [02:39] again, as with computed can include multiple computed, the same with methods can also include lots of different methods created. So in our case, the value that we want to pass here is going to support both the from and the to. So what we're going to use here is the [02:58] employee state, the filters lookup, and we want to walk into the salary part. But what is important? In one case, we want to update only the from. In other case, we want to update only the to. Maybe there would be a need to update both so we can make it a partial so we can effectively use TypeScript features. [03:19] And we're going to patch the state again similar as above. Patch state accepts the store parameter, and the second parameter going to be the function that is going to update the state into a new value. And again, since we are updating the filters, we [03:38] don't need to worry about these, the other attributes since they are just going to be copied. Only what we pass here is going to replace the whole slice. So what we're going to pass here is that. This is a new object that will include the filters. The filter over here would include [03:58] whatever was the state of the filters. And now we need to provide that, yes, there is also the salary because if we update, let's say, only the from and there was a to define, we cannot destroy it. So for this reason, unfortunately, we also need to go one level [04:18] deeper, and that would be destructuring the state dot filters dot salary. And finally, the value that we pass here, which is either the from number, the to number, or both. So that would be dot dot dot value. As [04:38] you can see, this doesn't look very good. Well, it works. But it's not really something that would be very convenient to work with. So in such use cases where we need to support multiple nested levels of immutability, it could make sense to reach out to a specialized library, in our case, Ymer, which is going [04:57] to significantly simplify the way that we need to walk into the nested objects and nested arrays. So what Ymer provides is, first foremost, one method that has different flavors and different APIs, the method is called produce. So we are going to write mutating [05:17] code, and Ymer is going to guarantee that the original object doesn't get mutated. So this is the code that we've had to write manually using the patch state, and here comes the alternative that comes from AMER. We invoke the produce function and [05:37] pass whatever the current state is. Now we know what the state is because the patch state will basically inject it to us. And we're going to mutate, not the state, but the draft. The second parameter to produce is a callback function. So we can modify the draft, we can mutate it, [05:57] and the overall result of the produce function is going to be the state which should be immutable, and it will remain immutable. And everything that we have changed on the draft is going to be remembered and applied back into the state object in an immutable fashion. So what do we want to mutate [06:17] in this case? Well, in this case, this is just going to be draft dot filters dot salary. And bear in mind that if we know what is the shape of the state objects, then Immer and its typescript types knows that the draft is going to be a writable draft of [06:37] the very same structure. So the draft is a writable structure of the whole state, filters is a writable draft of a piece of the object salary is yet again, a writable draft of a smaller nested piece and so on and so forth. So in a not really correct way, we could basically replace [06:57] whatever was the salary with the value. But this case, TypeScript yells at us that this could include the from or the to or both or even none of them, and salary has the required pieces. So, basically, undefined is not assignable to number. So to make it correct, we could use, for instance, object assign [07:17] that whatever was present on the drafts dot filter dot salary, please overwrite it with whatever we have within the value. So if there were 2 properties, then they could get overwritten. What is important in this case is that this piece is [07:36] mutable. This line is mutable. And the mutated draft is going to be used to create a new state object in an immutable manner, something that PUT state requires. As we can see, everything works correctly and remember to check out the ngrximmer package.

egghead
egghead
~ 12 minutes ago

Member comments are a way for members to communicate, interact, and ask questions about a lesson.

The instructor or someone from the community might respond to your question Here are a few basic guidelines to commenting on egghead.io

Be on-Topic

Comments are for discussing a lesson. If you're having a general issue with the website functionality, please contact us at support@egghead.io.

Avoid meta-discussion

  • This was great!
  • This was horrible!
  • I didn't like this because it didn't match my skill level.
  • +1 It will likely be deleted as spam.

Code Problems?

Should be accompanied by code! Codesandbox or Stackblitz provide a way to share code and discuss it in context

Details and Context

Vague question? Vague answer. Any details and context you can provide will lure more interesting answers!

Markdown supported.
Become a member to join the discussionEnroll Today