Vue 2 Internal Features from the Ground Up

Challenge 10: Solution

Evan You

Evan You

Creator of Vue.js
Vue 2 Internal Features from the Ground Up

Check out a free preview of the full Vue 2 Internal Features from the Ground Up course

The "Challenge 10: Solution" Lesson is part of the full, Vue 2 Internal Features from the Ground Up course featured in this preview video. Here's what you'd learn in this lesson:

Evan walks through the solution to Challenge 10.


Transcript from the "Challenge 10: Solution" Lesson

>> Evan You: Shared instance. We've noticed that when view, a view instance takes some data in, the default behavior is it proxies all the root level properties on that data object onto the view instance itself, right? So we can in fact use the view instance as some sort of reactive data store or a model which makes it look very similar to MobX in that sense.

So if we have, because this is a single instance we can use directly, just do this, count:0.
>> Evan You: And more importantly, we can colocate the logic for possible state changes into this instance. And we use methods for that, right? So if we have this.
>> Evan You: So now, we have something that's pretty neat.

We have its state in the way of state can possible change in one place. And because the state object itself is reactive we can just directly [COUGH] reference inside other components without even worrying about turning it into data first.
>> Evan You: So now this counter component will actually work, because when state was processed by view, view instance is reactive by default.

So the idea that it is reactive means when you access state.count, this would trigger a getter, which registers the dependency, which in turn calls this whole render function to be reactive. And later on, when state count changes, this render function will be called again, triggering the counter component to re-render.

>> Evan You: And in our app here, it still needs a register counter, obviously. And we still need to somehow proxy the call to the ink but now instead of directly manipulating the state here, we're just calling a function here. So [COUGH] this may seem redundant for this little example.

But the good thing is, we are hiding the details of how the state actually is mutated. So the details of how state actually is mutated is co-located with the state with the store itself. In real apps, this logic can be much more complex than just incrementing a count.

This can involve going to an API, fetching some things, doing filtering, comparisons and all that and eventually mutating the state. And if these state logic is inherently coupled with the state instead of couple with the logic of those components, then it makes sense to take out of these logic and put them in the centralized place, too.

So this would become your go to place. So this state could be-
>> Evan You: So this pattern actually applies very well. So let say you have an app and you have different kind of data in your app. So you can literally change the naming to a store and assign them names like userStore, productStore, and each of them is dedicated to dealing with one specific domain or app.

And then they can be directly imported and used in all your components anywhere you want. Even reference them directly inside render functions. So this pattern actually works pretty well for medium sized apps. And if this kind of domain model based state management is what you prefer, you can even extend it, to build upon it for bigger apps.

But this is already getting pretty close to VueX which is our, the pattern is designed to handle bigger skills. And if you've used VueX before you will notice that we can rename a few things, for example, we can call this thing the store and-
>> Evan You: VueX has this concept called mutations and actions.

So the difference between mutations and actions is mutations are the code or the functions that actually changes your state, actually mutates your state. So this is where the mutation happens. And they must be synchronous. The reason that they must be synchronous is because Vuex has a devtools integration.

If you've seen the devtools integration, you know there's the time travel feature and we have snapshots of your state whenever a mutation happens. If you want to take snapshots then it is critical that the mutations be synchronous because you can compare the before and after immediately after the function is called.

If a mutation can contain arbitrary asynchronous operations, then after you call the mutation you don't really know how long you have to wait until your state has actually changed. So that can make the snapshot comparisons a lot harder to implement. So and also, asynchronicity and the actual mutation of your code is better separated, because asynchronicity is really sort of a complex topic of its own, right?

So essentially in VueX the concept of actions and mutations are really just meant to separate asyncrhonousity from the actual procedures of mutating your code. Also inside actions you can do a lot of things like calling to external APIs, whereas your mutations will be focused just on dealing just with the state.

Your mutations will take some arguments and mutate the state, and that's pretty much all their responsibility. While in actions there's a lot more things you can do and it can involve asynchronously.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now