Akryum / vue-supply

Create resources that can automatically be activated and deactivated when used (like subscriptions)
159 stars 16 forks source link

Data Observables, Observers and Unsubscribers #1

Closed zoomclub closed 7 years ago

zoomclub commented 7 years ago

Is the main purpose here to toggle a data source? If I'm grasping the intent then why not use Observables and Observers?

Using a Vue instance might be observable-ish, but introduces yet more concepts IMO and misses out on the rich paradigm and API that stream libraries like RxJS already provide.

Akryum commented 7 years ago

The main purpose here is to consume Observables in an automated way to optimize real-time data usage and toggle subscriptions only when components really need it.

Frizi commented 7 years ago

RxJS is a great library, don't get me wrong, but why should we introduce it if Vue's watchers are good enough for the job? There is no reason to make things harder and more complicated than they need to be.

Akryum commented 7 years ago

Plus, you get all the features of a Vue instance to create computed properties and such, all of which is already available with Vue core without any additional library.

zoomclub commented 7 years ago

@Akryum Thanks for the clarification. There just seems to be many similar approaches already, for instance a router route can also be used to manage data for a component. Seems the options for data IO are fragmented IMO. Had a look at FeathersJS, seems robust and consistent.

@Frizi Are Vue's watchers good enough for the job? I think they are useful yet they can not give me the toolbox of operators that RxJS provides. For many of my tools RxJS is required, to try and rebuild the required operators with Vue is simply not a good use of production time.

zoomclub commented 7 years ago

@Akryum I agree a Vue instance has a lot to offer yet it is not a API that provides a full rack of operators that can be piped together like legos to build almost any kind of process required.

Akryum commented 7 years ago

Using external reactive data sources efficiently has been a pain point when working with meteor or apollo and vuex. I created this package precisely to solve this problem, and it is not intended to be the silver bullet for other data processing which I think dedicated libraries like highland.js are better at. BTW you could use both vue-supply & RxJS if you wish.

Also, I chose to go with Vue instance to reduce the introduction of new concepts, since vue-supply just basically uses standard data/computed properties and methods. The other big advantage is that you can directly use things like vue-meteor-tracker inside a Supply, since it's just a simple Vue instance after all:

import { Supply } from 'vue-supply'
import { Messages } from '../collections'
export default new Vue({
  data () {
    return {
      messageList: [],
    }
  },
  // Realtime data from Meteor
  // special option provided by vue-meteor-tracker
  meteor: {
    messageList () {
      return Messages.find({}, {
        $sort: { date: -1 },
      })
    },
  },
  // Automatic activation
  methods: {
    activate () {
      // Meteor subscription
      // Special method provided by vue-meteor-tracker
      this.messagesSub = this.$subscribe('private-messages')
    },
    deactivate () {
      // Special method provided by vue-meteor-tracker
      this.$stopHandle(this.messagesSub)
    },
  },
})

And inside a component:

import { use } from 'vue-supply'
import PrivateMessages from 'supplies/private-messages'

export default {
  // Will automatically start and stop the necessary subscriptions
  mixins: [use(PrivateMessages)],

  computed: {
    privateMessages () {
      return PrivateMessages.messageList
    }
  }
}

I think declaring data usage at a component-level instead of routes helps decoupling the components from the structure of your app, avoiding errors like forgetting to add one of the hundred required subscriptions for a page (it simpler to reason about what the data is consumed by a component when looking at it directly with everything at a glance instead of a route code far away in the project), maintaining and evolving those components (you don't need to worry about changing all the potential routes where this component potentially is).

Akryum commented 7 years ago

@zoomclub Did we answer your questions?

zoomclub commented 7 years ago

Not sure, strikes me as a take on the basic un/subscribe concept. Is the de/activation automatic only when a component is first created? Can de/activation happen at runtime? Can the source data stream be swapped with a different source during runtime?

These runtime options are likely not possible due to how the reactivity of a vue-instance works at this present time, according to https://vuejs.org/v2/guide/reactivity.html

zoomclub commented 7 years ago

Still an open issue, can close it if you prefer? At this point I'd just have a few things to clarify:

• For my scenario I would need the de/activation to also be possible at runtime. • Maybe look at vue-rx for some beautiful automatic un/subscribe solution. • Realize that vue-rx does all it's un/subscribe based on component lifecycle too. • Find the best way to add runtime de/activation un/subscribe in auto reactive frameworks.

Akryum commented 7 years ago

You have a few ways to manually use a Supply. The low-level way with grasp() and release():

import TestResource from 'supply/test-resource'

console.log(TestResource.consumers) // 0
TestResource.grasp()
console.log(TestResource.consumers) // 1
// Wait for the supply to be ready (pending subscriptions, ...)
await TestResource.ensureReady()
// Use the data here
console.log(TestResource.someData)
TestResource.release()

The high-level way with consume:

import { consume } from 'vue-supply'
import TestResource from 'supply/test-resource'

// This will grasp and wait for the supply to be 'ready'
const release = await consume(TestResource)
// Use the data here
console.log(TestResource.someData)
// When you are done with the supply, release it
release()
zoomclub commented 7 years ago

Thanks again for the clarification. A major aim of mine is to simplify and it seems that it takes a lot of vigilance to keep it that way, I'm a proponent of RxJS for this very reason. I'm past the valley of decision on this one so I'll close the issue and as they say, catch you on the flip side 💯