When we have something like this, the user will obviously define a model with properties and actions. We are actually building two types in one fluid interface. Basically, this first part constricts what you say, the user base.
Then we could split this up, and we say the user is taking the user base, and extend that with some actions, so this goes just basically the same as we already have. We now have changed our application, but actually, nothing really changed. This is still the same application. We just split into types.
Since this works this way, you can actually chain many action blocks together, and give each action block its own local state. While you have this, you could basically say, "I want to reuse this user base concept, both on my server and in the clients."
In the clients, you can say, "The user is extended with these kind of actions," and on the server, you can have completely different actions, for example. Actually, we could even separate this a bit further, and say while we have the user actions as separate type, which start off, an empty model some inaudible properties, it's just actions.
Then the actual user adds the composition of the user base with the properties and user actions. Because types are first class immutable citizens, we can compose them together in all sorts of way. They all can have their own life cycle hooks, their own actions, and introduce their own properties, etc.
Now, let's refer just a little bit, and build something actually useful with this. What I want to look into is, this save function, you can imagine that this is quite similar for many types of your application. This is quite a simplified version of proper save.
Probably there should be better error handling, and probably the save function should be debounced, so that this don't calls too often. Probably a request should be aborted, as we saw earlier. There's a lot of generic logic involved which doesn't apply only to users, but also to any other concept you might have in your application.
Why don't we pull this whole save logic out of here and start introducing a new type? We're just going to introduce a dedicated type for this REST-specific logic. I start with an empty model again, and then we declare actions.
This is a simple type. It doesn't do anything specifically like inaudible , but it has the save logic, and it makes sure the inaudible listener is set up. Now, we can simply import this, this storable thing, and we can mix it into our type. We compose our base type, and we add storable to it.
There we go. This application still works the same as it did before, but we now extracted our logic for storing stuff. This makes our whole user definition a lot cleaner.
Actually, this is not reusable yet. The problem is, here we still have some hard-coded information, like this storable now always stores stuff in the users' collection.
It always stores it under the ID property. That might not be applicable to all entities in your application. Actually, I want to make this type more generic.
We can create a function, call it createStorable, and we say while inaudible a collection, it should store stuff in. What is the attribute? It should use this key.
Now, we export this function instead. To return this model from the function, and now, from our closure, we could just use the collection instead of the ID. We don't use the ID directly, but we use the attribute which stores the ID.
Now, this function has become completely generic. It lost any relation with the actual concept of a user. Now, we can simply go back to the compose, and don't use storable, but use the create storable function, and say it should be stored in the users collection, and as key attribute, please use the ID attribute.
Now, this on the fly generates a new type when we declare this user type. Still, we have an application that behaves the same, but we have now very generic logic, which we can reuse for different types as well for anything which is REST-like, like this type.
You can imagine that if you can do these kinds of things, like generic types on the fly for a REST-based systems, you can do the same for a GraphQL-based system, for a Firebase-based system. Because those generated types have access to the life cycle hooks as well, they can test their own logic.
They can get a snapshot of the instance they belong to, and can do all kinds of powerful stuff. With this, I want to this introduction tutorial to mobx-state-tree. Thanks for watching so far, and don't forget to buy cool gifts for people around you.