vuejs / vuex

🗃️ Centralized State Management for Vue.js.
https://vuex.vuejs.org
MIT License
28.41k stars 9.57k forks source link

Nested module registration fails when parent module was not registered before #1079

Open nirazul opened 6 years ago

nirazul commented 6 years ago

Version

3.0.1

Reproduction link

https://jsfiddle.net/6mb7p617/3/

Steps to reproduce

Open devtools and look at the error. You will se a "addChild" error.

What is expected?

I was under the impression that neste vuex modules are possible without first registering the parent module.

What is actually happening?

I can register foo/bar without first registering foo as a vuex module.

This could come in handy when using vuex in plugins that want to have a plugin namespace and multiple vuex modules:

store.registerModule(['my-vue-plugin', 'my-first-module'], {
  // ...
})

I'm aware that this might be intentional. Maybe it's enough to clarify this in the docs under "Dynamic Module Registration" that you need to register the parent scope first.

LinusBorg commented 6 years ago

Yes, that's expected - a child module can't be registered without its parent being present. I think that's pretty obvious and self-explanatory, though- a nested object (of whatever kind) can't work without a parent object to be nested in.

What made you think this could work otherwise? Maybe that's thepoint we have to clarify.

nirazul commented 6 years ago

After looking at the documentation and seeing:

// register a nested module `nested/myModule`
store.registerModule(['nested', 'myModule'], {
  // ...
})

... I was pretty sure that it should work, as I thought that a module is more like a namespace instead of a real parent/child relationship. The thing missing is probably that "nested" is already a preexisting module.

But you're right. It's pretty obvious when thinking about modules as objects.

posva commented 6 years ago

A dev warning may also be easy and nice to have

hackel commented 6 years ago

I guess this wasn't obvious to me. Why not just check if the parent exists, and if not create it automatically? It seems pointless to have to include modules: {nested: {}} in my root state. I'm trying to keep my component's state isolated so that it is reusable and doesn't have any dependencies on the root state.

Edit: It looks like I can't even check it first without relying on a non-public API. e.g.

if (!this.$store._modules.get(['nested'])) {
  this.$store.registerModule('nested', {})
}

Am I missing a better solution?

kamerat commented 4 years ago

In my use-case, I have 3 different pages that is considered the same category. They are all different types of orders. I would then like to have them all under a module called orders. Example: orders/logs, orders/list, orders/contacts Reason being I would like them to be organized together since they are the same category.

I would not like to have the orders module registered if a user has not navigated to one of the three pages. Therefore, I would like to dynamically register the modules individually.

By doing

this.$store.registerModule(['order', 'logs'], {...});

I assume it will generate the order parent for me as it is not yet defined, else just append the child.

By the current way you are describing it to work, I would have to first check if the module orders is registered and add it if it is not already there.

this.$store.hasModule('orders') 
// -> add if not registered, continue else

I would love to hear why you think it is a bad idea for vuex to automatically create this if it does not exist, @LinusBorg For me, this would be a useful feature.

kiaking commented 4 years ago

I get your point, though I think the behavior should be kept as is due to semantics reasons. The module is really an object tree. It requires to have a parent module, and yeah, maybe we could add an empty module automatically, but that might cause problems when you really need some state to be in the parent module.

For your situation, personally, I would recommend not using an empty module but use prefix instead. You can name each of your module like order_logs, order_list and such. You could even use slash if you want.

{
  'orders/logs': {...}
  'orders/list': {...},
}

And do;

this.$store.registerModule('orders/logs', {...});
kamerat commented 4 years ago

Thank you for the reply @kiaking, I think a prefix could be a solution indeed! Only downside would be that the vuex dev-tools would be polluted with many nodes due to them not being nested.

kiaking commented 4 years ago

Only downside would be that the vuex dev-tools would be polluted with many nodes due to them not being nested.

Ah good point. Yeah that's true.