Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a standard/elegant way of achieving Firebase-like reactive objects without Firebase?

The thing i like about realtime databases like Firebase is their push features. for example vuefire makes it incredibly simple to have self-updating objects without stringing up hundreds of socket listeners and callbacks.

This is an example:

data(){
  return {
    books: []
  }
},

created(){
  axios.get('/books', (books) => {
    this.books = books
  })
}

In order to add db reactivity to this, I need at least 3 events “book-created”, “book-updated”, “book-removed”.

Pusher.on('book-created', (book) {
  this.books.push(book)
})
Pusher.on('book-updated', (book) {
  let b = _.find(this.books, {id: book.id})

  if(b){
   _.extend(b, book)
  } 
})
etc..

It gets quite hairy when you have many models and many views, some views have a different set of books so I can’t just have one standard books vuex variable. Is there a sensible/fast way to approach this?

I can certainly abstract the event sending on my backend so all my models push events automatically. but the front-end is where i’m confused.

like image 946
CodeOverload Avatar asked Apr 02 '18 12:04

CodeOverload


1 Answers

I never worked with pusher before, and I don't know exactly what's the "different set of books" you're referring to, but I think I can give you some starting point to make your code look a bit more elegant.

The first thing I suggest; do not try to reinvent the wheel, use component mixins. Just create a mixin like you'd normally consume your backend, make it work with some dynamic options (that you can set in the component's data()) and import it on every component you need the same functionality, with different options.

Example (you'll need to adapt it accordingly)

// Create an ES6 module and export this function, or the whole mixin
// (in that case export the mixin instead)
const initPusher = function ({pusher, collection, key, events}, component) {
  collection = component[collection]

  pusher.on(events.created, (record) => {
    collection.push(record)
  })

  pusher.on(events.updated, (record) => {
    let r = _.find(collection, {[key]: record[key]})

    if(r){
     _.extend(r, record)
    } 
  })
}

const PusherMixin = {
  methods: {
    // You can add some common methods for all your
    // components making use of this mixin
  },
  created () {
    initPusher(Object.assign({}, {
      pusher: Pusher,
      collection: 'collection',
      key: 'id',
      events: {
        created: 'book-created',
        updated: 'book-updated'
      }
    }, this.pusherOptions), this)
  }
}

new Vue({
  el: "#app",
  mixins: [PusherMixin],
  data () {
    return {
      books: [],
      pusherOptions: {
        collection: 'books',
        key: 'id',
        events: {
          created: 'book-created',
          updated: 'book-updated'
        }
      }
    }
  }
})

My second suggestion implied a manipulated array prototype with some custom methods and hooks to trigger events and XHRequests but after finishing the code for the mixin, I found out that extending the array's prototype with more methods was adding too much complexity, and a good mixin was totally the opposite of that.

If you want to go deeper, you may want to pay a look to RxJS and observables. You can build something on top of that with Pusher to get something like a Firebase real time object.

  • Tutorial: https://blog.pusher.com/building-realtime-applications-with-cyclejs-and-rxjs/
  • RxJS: http://reactivex.io/rxjs/
  • Official implementation for Vue: https://github.com/vuejs/vue-rx
like image 158
Frondor Avatar answered Oct 20 '22 02:10

Frondor