cierrateam / nuxt-parse

A parse nuxtjs plugin
23 stars 4 forks source link

How to use it under asyncData . #23

Open thunderwin opened 4 years ago

thunderwin commented 4 years ago

How to use it under asyncData .? there is no THIS.. or it's not possible?

vittoriodev commented 4 years ago

Thank you for your message. Let us check. I think atm there is no preperation for it.

woutercouvaras commented 4 years ago

I think it needs to be added to the nuxt ctx for it to be available. I'm trying to figure this out for myself. If I get something working, I'll definitely share it.

woutercouvaras commented 4 years ago

I managed to attach Parse to the nuxt context...the problem that I then had was overcoming the different import requirements based on Server vs Client context - see the Parse docs: https://docs.parseplatform.org/js/guide/#getting-started). i.e

Of course, as we're discussing here, if you're using nuxt for SSR - it runs in both contexts...

I knocked my head for quite some time and actually switched to GQL (which I've managed to get working, but I really wanted to be able to use the SDK...)

I found this which was helpful: https://github.com/parse-community/Parse-SDK-JS/issues/1091

I've added the "config.node" object as highlighted at the bottom of the page and then I've also change the 'module.plugin.js' file to look like this:

export default ( context, inject ) => {
    let Parse = undefined
    if (process.client) {
        Parse = require('parse')
    } else {
        Parse = require('parse/node')
    }

    Parse.initialize('<%= options.appId %>', '<%= options.javascriptKey %>')

    Parse.serverURL = '<%= options.serverUrl %>'

    // attaching it to the nuxt context
    context.$parse = Parse
    inject('parse', Parse)
}

With this, the content is rendering on the server when needed and I'm not getting any errors.

With this change, one can make a successful change in asyncData as follows:

async asyncData(ctx) {
    // this is a contrived example - running a cloud function
    const product = await ctx.$parse.Cloud.run("helloFromTheCloud")
    return { product }
  },

@vittorioe I've not yet tested the middleware feature with these changes, but as soon as I've, I'll feed back, in case you'd like a PR.

woutercouvaras commented 4 years ago

It seems perhaps I spoke too soon :)

Though my change has worked to get the data loading on the server, any subsequent, client side routing doesn't quite seem make the data available as expected.

If I look at my browser's network tab, the object data is being fetched in full, but in Vue I only have a subset of the data available - e.g.:

_localId:undefined
_objCount:0
className:"Product"
id:"sJCM8DNvWh"

The rest, though returned by Parse, is simply not available. I saw some reference to a fetch method in the docs, but using that made not difference either. I can only think that it's due to the /node package that's initially loaded. As soon as I refresh...the data is all there.

I'll add any further findings here.

pcg92 commented 4 years ago

So.. its not possible to use parse in asyncData?

woutercouvaras commented 4 years ago

It is possible. I was just thrown because I was expecting the full objects to be returned, but they aren't. I've since learned that the SDK was built to work as a drop-in replacement for Backbone models, in Backbone apps. This means that you have to use getters and setters to work with the property values.

Sadly this is a problem for Vue apps because it means that you lose all reactivity (because vue doesn't see the property values). I've ended up using the REST api for most of my app to date.

Hmmm...as I'm typing this though, I'm wondering if watchers might help. I'll test that out later today and report my findings here.

woutercouvaras commented 4 years ago

Hi, sorry for the delayed reply.

@pcegarra - to answer your question, you can totally use it in asyncData as I mentioned in my post above. The problem I've been facing has not been getting data, but rather how to make the data reactive once you have it. This is in the context of my my comment right above this one.

When I wrote this last reply, it sparked a thought about using a watcher to be notified of an object change and then to handle that change accordingly. It's not nice, but at least I'm able to move forward in a reactive way.

As an example, I've been storing my logged in user in vuex. Naturally, I used a computed property to get the data from the store. The issues is, whever the store changed, the gui wasn't updating. I tried adding a watcher to the computed property, but it didn't seem to work. I found this article which was really helpful:

https://dev.to/viniciuskneves/watch-for-vuex-state-changes-2mgj

Now, in my header component (as an example), I'm getting full reactivity, with the solution below. It's a sad amount of boiler plate, but it's working for now. I'd love it if anyone might have a better suggestion for handling this in a more elegant way. It's probably worth writing a utility to do this. If I get there, I'm happy to share it.

export default {
  data() {
    return {
      showProfile: false,
      showMobileMenu: false,
      user: {
        name: undefined,
        surname: undefined,
        username: undefined,
        email: undefined,
        profile: undefined
      }
    }
  },
  created() {
    if (this.$store.state.user === undefined) {
      this.$store.dispatch('SET_USER', this.$parse.User.current())
    }
    const user = this.$store.getters.GET_USER
    this.setUser(user)

    this.unsubscribe = this.$store.subscribe((mutation, { user }) => {
      if (mutation.type === 'SET_USER') {
        this.setUser(user)
      }
    })
  },
  methods: {
    setUser(user) {
      this.user.name = user.get('name')
      this.user.surname = user.get('surname')
      this.user.username = user.get('username')
      this.user.email = user.get('email')
      this.user.profile = user.get('profile')
    }
  },
  // Don't forget to unsubscribe!
  beforeDestroy() { 
    this.unsubscribe()
  }
}
woutercouvaras commented 4 years ago

Are you getting what looks like an empty object with an id? If so, did you read my earlier comment about using the .get() method to read property values?

pcg92 commented 4 years ago

Hi, Im trying to send the ParseObject in JSON on the fetch method and then Im trying to construct the ParseObject in the frontend, what do you think?

woutercouvaras commented 4 years ago

I'm not sure if I'm understanding you correctly, but here goes.

If you're using the SDK, you can't (because of the reasons above). The "data" of the parse object is only exposed via that .get() method. If you look at my example above, you'll see that if you fetch the logged in user via the sdk, like this: const user = this.$parse.User.current() you'll notice that you get something like this back:

image

the only way to access the "name", for example, would be user.get('name'). If you want to deal with JSON, use the REST API instead - I do this in some parts of my code as it's just way easier to get stuff done.

In my example above, you'll see what I'm doing where I use the SDK, but want my properties to be reactive (I know it's not ideal...this involves writing loads of non-dry boilerplate code - writing a little lib would be better - if you have the time).

I would say one last thing. If you're working with array of data, I would almost certainly use the REST API. You don't wan to loose those db references and converting the objects from Parse objects to standard objects just increases those risks. If you use the REST API, you get all the required data in the JSON response from the server...way safer and easier to work with.

I hope this helps and I'm sorry if I've misunderstood you :)

pcg92 commented 4 years ago

Try doing this: const user = this.$parse.User.current() user.toJSON();

Then you are going to see the full object, the problem is that we cant send ParseObjects to the frontend, Im getting the same problem with React Next

woutercouvaras commented 4 years ago

Right, sorry, I understand what you mean. Yeah, I spent hours on this, trying all sorts of things. I ended up using the rest api. It's a little cumbersome, but at least you can move. I've only been using the SDK in the admin part of our app (and only in part), which doesn't need SSR - it's a SPA.

If the sdk could work well across the two...it would be killer!