9

I am working on a Vue plugin for Pouch/CouchDB which will be open sourced, but as long as i can figure out an issue i am having:

Currently i am trying to make the plugin closely to resemble Vuex, that has an internal state, and detect changes, and render the view when they happen.

Inside the Vue instance i am initializing an object, and within that object i am trying to make two or three objects reactive, with defineReactive, until here its good.

But when i try to change some values inside that object, the changes are not propagated to the View. BUT if i explicitly call this.$bucket._state.projects.__ob__.dep.notify(), the changes propagate.

The current object representation of the Vue instance is like this: Vue { $bucket: { _state: { projects: {} } } }

$bucket._state has been initialized with defineReactive. which i believe it should work, but i am not sure what's the exact problem in this case.

Any idea?

A partial of the code, the class in here is almost similar to Vuex.Store({})

    constructor(schema = {}) {

    // Getting defineReactive from Vue
    const { defineReactive } = Vue.util;

    // Ignored Schema Keys
    const ignoredKeys = [
      'config',
      'plugins'
    ];

    // Internal Variables
    this._dbs = {};

    // Define Reactive Objects
    defineReactive(this, '_state', {});
    defineReactive(this, '_views', {});

    // Local Variables
    if (!schema.config) {
      throw new Error(`[Pouch Bucket]: Config is not declared in the upper level!`);
    }

    // Init PouchDB plugins
    if ((schema.plugins.constructor === Array) && (schema.plugins.length > 0)) {
      for (let i = 0; i < schema.plugins.length; i++) {
        PouchDB.plugin(
          schema.plugins[i]
        );
      }
    }

    // Initializing DBs that are declared in the schema{}
    for (const dbname in schema) {
      if (schema.hasOwnProperty(dbname) && ignoredKeys.indexOf(dbname) === -1) {
        this._initDB(
          dbname,
          Object.assign(
            schema.config,
            schema[dbname].config ? schema[dbname].config : {}
          )
        );

        this._initState(dbname);
      }
    }
  }

1 Answer 1

17

I think you don't need to use these internal APIs like Vue.util.defineReactive or this.$bucket._state.projects.__ob__.dep.notify()

Because Vue itself is reactive, you can use a Vue instance to store the data. There is no need to reinvent the reactivity system.

Create a Vue instance in the constructor:

this.storeVM = new Vue({ data })

and use getter to delegate the .state to storeVM.$data

get state () {
  return this.storeVM.$data
}

so when you access myPlugin.state, you are accessing the data of the Vue instance.

I created a very simple reactive plugin example: http://codepen.io/CodinCat/pen/GrmLmG?editors=1010

No need to use defineReactive or notify the dependencies by yourself if a Vue instance can do everything for you. In fact, this is how Vuex works.

Sign up to request clarification or add additional context in comments.

2 Comments

are there any issues with cpu or memory overhead when creating a separate instance just to have a couple of reactive properties?
@Andre12: Since vue 2.6.0 you can use Vue.observable, which does not have the same overhead as creating a whole new vue instance.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.