We will expand our UI, and give the user the possibility to edit his wishlist. We will use the earlier defined actions. We also will use model clones only to modify data temporarily, and after approving the changes, apply them back to the original model.
In this lesson you will learn:
clone
to create a full, deep clone of any model instanceapplySnapshot
to update the state of a model instance given a snapshot.Instructor: [00:00] It is time to add some edit capabilities to our wish list application. So far, it's possible to render the data, and even make sure that the UI updates whenever the data is changed. It is not possible to change the data yet, at least not from the UI.
[00:18] Let's start by introducing a new component, the wish list item edit. I like long names. This component takes responsibility of editing the fields of an individual entry.
[00:34] Of course, this is based, again, on React, the observer bindings from mobx-react. This component will have quite some events, so let's use a components class for this one.
[00:48] Let's assume that we pass it the item it has to edit, so it has one property, the item. We pick it from the props, and we render the necessary HTML markup.
[00:58] We create input fields for each of the properties of an item. We copy/paste a little, and for each of the fields, we generate an event handler. There we go.
[01:13] Now we can render three input boxes, and we have defined three chains handlers. Let's implement them.
[01:21] When the name changes, we receive an event. From that event, we pluck the current value of the input. That value, we assign to the name of the item. The other two are pretty similar, so just copy/paste them.
[01:38] The only one which is a little bit special is on price chains, because you want to make sure we actually get a number. Otherwise, mobx-state-tree will throw us an exception that the value we are trying to assign is not valid. If it's not not a number, then it's a number, and we can update the price.
[02:06] Finally, we export this component. It's, of course, an observer again because it needs to react to the changed image so that the inputs get eventually updated, representing the new value assigned.
[02:23] Now we have a nice edit form for an individual wish list item, and we should start using it. I intend to call this one from the wish list item view. We want to capture the state of whether the item is currently in edit's rendering mode or no more rendering mode.
[02:46] For that, I want to use a local component state. We could store the state also in mobx-state-tree if we want, or we could use observables for it. For now, just for simplicity, for familiarity, I'm creating a simple component that has a classic React state.
[03:04] We restructure the component a little bit, so it now has a render function, and say by default, its editing is false, and that [inaudible] can toggle the item to edit mode.
[03:22] If we press the edit button, we simply update the state and set isEditing to true. So far, this doesn't have any value, so we should also make sure that the rendering renders differently if it's editing.
[03:43] I simply say this, but state is editing. Then we render this item editable, and otherwise, we render it as currently.
[03:54] This is where our wish list edit component comes into play. We pass it our [inaudible] item, and this should be enough to make a component editable.
[04:04] You now can change it. We can say that we want a newer model of this Lego Mindstorm thing, but we have no way to leave this edit [inaudible] so let's add a simple button for that, and cancelEdit is, of course, pretty straightforward. It just sets the editing state to false again, so now we can toggle between those states.
[04:32] Actually, there is something off. If I edit this item and I update the price, so I make it super expensive. Then I, "Oh, it's a mistake," I cancel it, and then we see that the price is still changed. That's a bit annoying, and it's simply because of the fact we pass this item directly to the item editor, which updates the fields on chains.
[04:57] Of course, we could fix this problem by, in the item editor, keeping local state until it's persistent. Since we are using mobx-state-tree, we can solve this more elegantly. What if we don't pass the item to that component, but instead just pass a clone?
[05:16] I'm going to import the clone method from mobx-state-tree. Clone simply takes the type of object you give it and takes its snapshot, and then instantiates a new instance of the same type with the same snapshot, so you get basically a literal copy of the same thing.
[05:39] Now if you start editing, we can set the clone to the clone of the item which was passed in, and over here, we pass in the clone. Now we're not editing the original anymore, but the clone instead.
[05:54] We edit it, and we make some changes over here, and we cancel, and we're back at the old state. Of course, that means that we also need a button to save the changes, so let's introduce another button. You have the nice emoji, as well, and say on safe edits, we need to copy back the changes which were made to the clone to the original item.
[06:19] That is pretty simple, because we have all these snapshot functions. We import getSnapshot and applySnapshot. Then when we save it, we say, "Please get me the snapshot of the clone," so capture all its state as raw data, and then given that snapshot, apply it to the item that was passed into this component.
[06:43] This will take all the states and apply it to this item, and do so with the minimal amount of modifications possible. Then we set edit to false, and the clone to [inaudible] .
[06:56] Now it's possible for me to edit this item and change the price. This happens on the cloud, so I can either abandon the changes, or I can say, "Well, it has become cheaper, so let's save these changes," and now the price is updated.
[07:11] That is the power of using mobx-state-tree models. There are all these generic utilities like getting snapshot, applying snapshots back to an item, that can be implemented generically for you by the library because it can reason about models in a very generic way.