1
votes

I am trying to refactor some code and move some code to the mixin. But I am getting different behaviour. I wanted an object to be shared across all instances of a component. So I had written something like below

<script>
export default {
  registryManager: new RegistryManager()
}
</script>

In the instances, I was accessing this by this.$options.registeryManager. Now I have moved this code to a mixin.

Mixin

export default {
  registryManager: new RegistryManager()
}

Component

<script>
import registryManager from './mixins/registryManager';
export default {
  mixins: [registryManager]
}
</script>

Let say you are having 2 components A, B. Earlier, All the instances of component A had one registryManager and All the instances of component B had one separate registryManger. With the use of mixin, All the instances of component A and component B are sharing one registry manager because regardless of how many components are using a mixin, only one instance of the mixin is created Is there any way to create one instance of the mixin per component to get earlier behaviour?

2
A new instance is created for every component that you import the mixin into. So not sure what you are trying to achieve?Utsav Patel
Not sure if that is the case. All the component are getting same instance of the registry manager.shiv garg
Is there any cleaner way of sharing a variable amongst all instances of a component?shiv garg
Yes, use a state management library like Vuex. If a mixin is written correctly, they behave like pure functions. Not sure If I understand your issue.Utsav Patel
Is there a reason why it was defined as an option? Is it supposed to be overridden somewhere?Estus Flask

2 Answers

1
votes

This is the expected behaviour. There is only one class instance, new RegistryManager() is evaluated only once in mixin module, Vue is unaware that registryManager needs to be instantiated multiple times.

Since there is a one-to-one relationship between component constructor and class instance, it can be assigned as constructor property.

This can be done globally:

Object.defineProperty(Vue.prototype, 'registryManager', {
  get() {
    if (!this.constructor._registryManager) {
      this.constructor._registryManager = new RegistryManager();
    }

    return this.constructor._registryManager;
  }
});

The class is also lazily instantiated this way. Can be placed inside install(Vue) {...} and used as a plugin.

Or locally as a mixin:

  beforeCreate() {
    if (!this.constructor._registryManager) {
      this.constructor._registryManager = new RegistryManager();
    }

    this.registryManager = this.constructor._registryManager;
  }
1
votes

You could create a factory method inside the mixin that expects an id (name of the component for instance) and returns an instance of a RegisterManager.

The mixin module will have to keep a map from ids to instances of RegisterManager.

Something similar to this.

const instances = {
}

export default {
  getRegistryManager: (id) => {
    if (!instances[id]) {
      instances[id] = new RegistryManager()
    }

    return instances[id]
  }
}

And then call getRegistryManager from your components.

<script>
  import getRegistryManager from './mixins/registryManager';
  export default {
   mixins: [getRegistryManager("ComponentName")]
  }
</script>