Welcome to our source speech repository about mobx-state-tree and powerpuffs.
- All the information is in the README 👌
- Source code of our livecoding is described here too ! 📖
- Feel free to open issues / PR 🤗
Final application link : https://powerpuff.herokuapp.com/
This is about creating our first model
#30 - Create the first model and instanciate it
Writing our first model of Powerpuff is pretty simple. We'll call it
Powerpuff
(damn, clever 🤓)
- Import
types
frommobx-state-tree
, this is the most common used API types
is used to ... type fields 👌, we can also use it to describe models ! Andtypes.model
is the way to go !- Here we create a model with only one field, a
name
which is a string ! - Ok, let's instanciate our model with
Powerpuff.create({})
Powerpuff
is our modelcreate
means we instanciate a new tree, a new instance{}
is the snapshot, the raw data, to use to instanciate a new powerpuff !
- Let's print it with a
console.log
!- As you can see, we use
powerpuff.toJSON()
to convert our tree to a snapshot
- As you can see, we use
- 🤔 oups, it doesn't work at all ! This is because, by default, a field is required
- Let's instanciate our powerpuff, it will be... hm...
Rebelle
(the french name of Buttercup) - Print it
- It works 🎉
#31 - Make fields optional
Sometimes we don't want fields to be required at creation
- To do so, we can use the type
maybe
, which sets the field tonull
if it's not defined - So now, when we instanciate our powerpuff with an empty snapshot, it works !
- And if we want to instanciate the model with a valued name, we still can do it 👍
#32 - Use more complex types
There are lots of available types provided by mobx-state-tree, find the entire list in the documentation
- Because a Powerpuff is not only a name but also has feelings 😡😊, we add the field
mood
to describe her - Powerpuffs' personalities are simple thus possibilities are limited. Let's use an enumeration to define them
- If you try to create a Powerpuff with a mood which is not in the enumeration, it fails (Don't try to counterfeit a Powerpuff 💪)
- Use a mood of the enumeration and now you can instanciate a new Powerpuff !
This is how we update our model
#33 - Updating the model, the natural way
As you must be aware, Buttercup is more
aggressive
rather thanhappy
. But the powerpuff is now instanciated, the damage is done. The unique solution to repair this mistake is to modify the instance.
- The natural way would be to set directly the
mood
attribute of the instance - As you can guess, it crashes 💥
#34 - Updating the model, mobx-state-tree way
To mutate the model, mobx-state-tree wants you to create an action. That way mobx-state-tree can create snapshots and the immutability of the state is kept 💖
- Describe the action within the function
actions
called on the model - We give a callback to
actions
function. This callback takesself
as parameter, it represents the instance itself. The function returns an object of defined actions - Here our action is very simple : we set the
mood
field of the instance with the givenmood
- Use this action to modify the instance, it works 🎉
There are functions that return values deduced from attributes: this is what we call views
#35 - Create a view
Do you know how old is our Powerpuffs now ?
- The best way to know is to add a
birthday
field to our model and then deduce the age from it 💡 - Btw, you can assign a value to a field when you create the model and mobx-state-tree will deduct the types like a grown up 👍
- Now we can create a view which computes the actual age of our powerpuff. Use the function
views
on the model to describe it - Like actions, views is given a callback which takes
self
as parameter and return an object of functions computing results - Here we write a simple getter to have the current age of the powerpuff and use it like an attribute
- Calling this view on the instance gives us the current age of the powerpuff 🎉
- Note that when we print the powerpuff, her age isn't part of the snapshot but it's memoized by mobx-state-tree
It can be handy to do some computing during the model lifecycle. mobx-state-tree exposes lifecycle hooks that you can find in the documentation
#36 - preProcessSnapshot
Instead of injecting a snapshot to create a new Powerpuff, we want to use a string describing her.
preProcessSnapshot
is called before the model instanciation 💁♀️- It takes the snapshot given to create the instance and returns a new snapshot matching the model
- Here we test if the given snapshot is a string
- If no, we assume it's a well formed snapshot and return it
- If yes, we extract the mood and the name and create a new object with this attributes matching the targeted model
- We can now use a sentence to instanciate our powerpuff, far much simpler ✨
#37 - afterCreate
Say we want Powerpuff's name to be always capitalized (it happens to forget to do it at instanciation, yes everybody can be mistaken, even better ones 😉)
afterCreate
is called after the model instanciation 💁♂️- It should be defined as actions to access the
self
of the instance - Here we simply capitalize the name and the job is done 🙌
With mobx-state-tree, it's possible to define models that depends on others
#38 - Nest models
Now it's easy to create a Powerpuff, they are spreading and it's becoming a mess ! Let's create a store to bring back some order
- We create a new model, which will be our centralized Store, called
Store
(yeah, still clever 🤓) - This model has a list of powerpuffs as attribute, which is an array of Powerpuff
- You can notice we introduced a new type :
optional
. It's likemaybe
but you can define the default value. Here we want an empty list of powerpuff if the snapshot doesn't have one - The model has also a function to add a new Powerpuff into the list
- Instanciate a store without snapshot, you get a Store with an empty list of Powerpuff 🎉
- Instanciate some powerpuffs using the store action
addPowerpuff
on the store instance and its list of Powerpuff is filled ✨
We have a centralized Store which contains a list of Powerpuffs and we can edit one from its index in the array. What if the edited one is always store.edited ?
#39 - Creating a reference
First of all we add the
edited
field and declare it as a reference
- We create a new field named
edited
which contains the reference to the currently edited Powerpuff 💡. You can see it like a reference which an editing screen can work with - This field is typed
types.reference
of thePowerpuff
model - We create an action to set this field, go on and call it
setEdited
! - Set the first powerpuff as the edited one 👍
- Print the
store
snapshot - Oups, it doesn't work 🙀
#40 - Reference an identifier
A reference needs an identifier
- We must add an
identifier
to our Powerpuff, a number is fine, let's call it... hm...id
😎 !! - The
id
is now required, we add it topreProcessSnapshot
as a random number (🤢, this is just for the demo) and to thebelle
Powerpuff instance as an arbitary number - Let's try to print the
Store
snapshot now! - 🎉 it works 🎉, you can see the snapshot doesn't copy the value into
edited
field (which is a reference), mobx-state-tree takes care of optimisations, what a good boy 🐶!
We are sick of console.log everywhere, maybe mobx-state-tree can help us ? Yes it can! 😎 Let's see some debugging tools it provides
#41 - onPatch
How can we track each changes done on our store ?
- We import
onPatch
from mobx-state-tree: it allows us to listen to all patches applied to our store. Here we use it to simply print these patches - We remove all the
console.log
and add theonPatch
listener to ourstore
instance, right after we created it - Now as we run the demo and we see patches applied to the
store
printed to the console - You can see 👀 that a patch contains:
- path
- action type
- value
- This is our favorite tool to debug our store 💚!
#42 - onSnapshot
What if we want to print the complete store snapshot after each mutation ? 🤔
- Ok this one, the last one, is an easy one!
- Replace all the
onPatch
byonSnapshot
and tada 🎉 🎉!! - You can see on the console, all the
store
's snapshots for each mutation 😁 - This is great and this is what allows mobx-state-tree to behave like a Redux store. You can see a demo from mobx-state-tree repository!
If you like this demonstration/livecoding, you can tweet about it! - @MilletDelphine and @fabienjuif