FiguredLimited / vue-mc

Models and Collections for Vue
https://vuemc.io
MIT License
626 stars 98 forks source link

Difference from Vuex #9

Open AlgoTrader opened 7 years ago

AlgoTrader commented 7 years ago

Can you please explain why to prefer vue-mc over vuex?

IamManchanda commented 7 years ago

Eagerly Waiting for the answer :)

Frondor commented 7 years ago

I think you misunderstood the scope of this library. You can use Vuex with these models and collections. Basically, these classes add an useful interface to our models and collections, validation and such. Vuex is just for state management

incraigulous commented 7 years ago

So, you would us collections and models in your store instead of plain objects? Do you do that yourself, or is that just in theory? It seems like there is some overlap in use-case. I would worry using both would be adding an extra layer of complexity to already complex vuex.

elcojacobs commented 7 years ago

I'm currently trying to combine vue-mc and vuex and I am having a hard time wrapping my head around this too. In each vuex module, I would like to have a standard way of communicating with the api. I also want to have a clear/active/saved state. So vue-mc offers some things that I need.

I could put the collection in vuex state and use the class interface to fetch/save. But in vuex, we can only change state with commits. So in a vuex action, I could call the .fetch and when the promise returns, I can commit the new data.

So to update some data, I think it should:

But still, it feels like there's a bit too much overlap. When using Vuex, I think only Vuex modules should access the API and UI components shouldn't. They just call Vuex actions. So I'd still have to define my own Vuex actions and commits for each endpoint and I still don't have a standard api interface. I'm still writing wrappers around vue-mc functions, which gives me room to do it slightly different for each module. The default state of vue-mc also potentially overlaps with vuex initial state.

So to me it seems that this is a very nice library for direct api communication for front end components, but when used in combination with Vuex, it doesn't fit that well. It adds an extra layer that doesn't seem to do that much. Only the clear/active/saved management is perhaps enough.

So based on my short investigation, I think I agree with @incraigulous. I would very much like to hear from others on how they tackled this issue and how to avoid overlap or unnecessary wrapping and extra layers.

Frondor commented 7 years ago

Probably the library is coupling too much functionality, and a better approach would be to modularize a bit some features into plugins(?) like optionally implementing validation (some people simply prefer using their own methods, since leveraging this to the library may look a bit shady), collection methods (which imho should be left to array native methods, like .filter and .find ), pagination is simple to accomplish with any array of items. Actually, I'm using Model only, since I prefer working with native arrays instead of Collection feature

pmackay commented 7 years ago

I think the docs would benefit from a section on the overlap with vuex, in what circumstances would it make sense to use both together or just this project alone.

rtheunissen commented 7 years ago

@pmackay very good idea. ✨

We don't currently use vuex at Figured so we're not very familiar with the overlap or interaction. Keep in mind that this was an internal library first so there's bound to be some oddities as we develop it for other use cases and projects too.

There seems to be an issue with the way the models and collections "magically" apply data and change properties. If, for example, you did a fetch in a vuex action, the fetched data will be applied to the model as soon as it's returned, having no knowledge of vuex. We could improve support for vuex by not applying the response automatically.

The first thing to know is that store.dispatch can handle Promise returned by the triggered action handler and it also returns Promise.

So we could do something like this:

// Maybe an option to indicate that we're using vuex?
model.setOption('vuex', true);

actions: {
    fetch({ commit }) {
        return model.fetch(commit);
    }
}

This might not make any sense because my understanding of vuex is very limited (have only read the docs a couple of times), but I'm sure we can find a way to make vue-mc work well with it.

rtheunissen commented 7 years ago

@Frondor

some people simply prefer using their own methods, since leveraging this to the library may look a bit shady

You can use your own methods. A validation method is simply a function that returns a string if the validation fails. You're also by no means required to use vue-mc's validation, and it won't be imported at all if you decide not to.

collection methods (which imho should be left to array native methods, like .filter and .find )

You can use native methods if you want, directly on the collection's models attribute, which is a native array. The collection methods is simply a syntactic alternative that you don't need to use.

rtheunissen commented 7 years ago

@elcojacobs

When using Vuex, I think only Vuex modules should access the API and UI components shouldn't. They just call Vuex actions.

I agree with this, anything interacting with the store should do so with actions, not on vuemc m/c directly like you would have if you weren't using vuex.

So I'd still have to define my own Vuex actions and commits for each endpoint and I still don't have a standard api interface.

At this point, yes you would still need to define actions and commits for each endpoint, which I agree is a lot of unnecessary wrapping.


I'm all in favour of providing better vuex support, we simply haven't been using vuex at Figured so we didn't design things with that in mind. But I do believe that the code is flexible enough to add better support for vuex. We should try to work backwards from what the ideal interface/API is like then see how we could implement that.

Those of you who are familiar with vuex, what would be the ideal behaviour here?

agustindidiego commented 7 years ago

Hey there. I'm interested in this topic. I believe that vue-mc is a very nice package and it provides me a lot of things I need. But I'm struggling with using it with vuex aswell. In my case, I ended doing just what you were mentioning, a single state to store the model attributes, and action that calls model fetch and when returned commit to set the state with the data, and a getter that returns and empty or a new model instance with the state data.

The issue I'm currently having is that is I try to change an active attribute, the change is not reflected in a binded element. An input text with v-model set to the instance.attribute, and an element rendering the attribute, when I enter a value in the input, the rendered element doesn't update. I added a listener to the change event to the instance, and the listener runs fine and shows me that the attribute is being changed.

Eitherway..., I found another package similar to vue-mc that has vuex support, vue-spine, it could be worth to check it and get some ideas on how to integrate vuex in vue-mc.

Cheers

Frondor commented 7 years ago

@rtheunissen yes but even if you use the native array in Collecions and your own validation logic, vue-mc overhead is still there. And doesn't feel right. See Laravel's Eloquent for example, it only handles the model instance, state, and queries (returning collections for many).

rtheunissen commented 7 years ago

@Frondor It's not overhead if you don't use it though? It's not in your code at all. The validation is a separate module, it's just not a separate package on npm. If you don't import it, there won't be overhead in your code.

AlgoTrader commented 7 years ago

I still cannot quite understand the lib scope. models and collections store data, state is also data. Vuex does not store plain objects, it converts plain objects into vue observables (vue reactivity system). Vuex provide data store plus mutations/actions and it has much cleaner integration with vue ecosystem. I don't think Backbone style models and collections is a step forward for vue

rtheunissen commented 7 years ago

I don't think Backbone style models and collections is a step forward for vue

It's a step sideways. 😂

We developed this library to solve a problem we were facing, so the focus was always on what is practical and what works well for us (and others, potentially). It's early days and I'd like to see this library develop into something that integrates better with the Vue ecosystem - vuex included.

Vuex does not store plain objects, it converts plain objects into vue observables

Vue itself converts plain objects into observables, so Model attributes are observable too, which allows them to be reactive.

I still cannot quite understand the lib scope

It's a bit of a mixed bag, no arguments there. Maybe it does try to do too much, but for projects that are happy to submit to its conventions, it does take a care of a lot for you.

minedun6 commented 6 years ago

Just like in ts, you can define interfaces to encapsulate your model data/properties, think of this library as a wrapper to help you manipulate objects instead of using properties bound to the vue instance. I think the library is heavily inspired from eloquent (Laravel). correct me if I'm wrong. It's in the repo's description "Models and Collections for Vue". Let's try to simplify things.

sifex commented 6 years ago

Hey all, just thought I'd comment my troubles. The best method for storing / interacting with VueX is to store each class as JSON (using the .toJSON() method), and using a getter to take the JSON back into a new instance of your Model, for instance:

getters: {
    getCurrentUser: function(state) {
        return new User(state.user);
    }
},
mutations: {
    updateCurrentUser: function(state, user) {
        state.user = user.toJSON()
    },
}

still going through refactoring collections, but I don't seem to have a use case for storing Collections in VueX..... nevermind.

Edit:

There may also be a bug in committing the class to VueX (even with the toJSON) as you're assigning to reference rather than assigning by value. To avoid this I just added a quick clone trick:

updateUser: function(state, user) {
    state.user = Object.assign({}, user.toJSON())
},

A really nice addition to see in VueMC (that may be bad programming practice) is that it checks if the constructor argument is an instance of itself. If it is - then return itself.

new User(new User(new User({ ... })))
pascaldls commented 3 years ago

Hi 2021 any news on using this with vuex would be nice to have in documentation