Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass propsData in beforeRouteEnter's next callback and call it before mounting #992

Closed
rhyek opened this issue Dec 7, 2016 · 9 comments
Closed

Comments

@rhyek
Copy link

rhyek commented Dec 7, 2016

So, after reading #779, #714 and running some tests of my own, I understand that the order of execution when using beforeRouteEnter is:

  1. beforeRouteEnter
  2. next
  3. All component's lifecycle hooks starting from beforeCreate down to mounted
  4. next's callback (which usually sets data on the vm)

So, if you're trying to display a nested property on your data object, you need to initialize it, otherwise you'll get runtime errors (e.g., cannot read property of null).

Sometimes it may be a little complicated/tedious to initialize data when it's structure is expected to be deep/complex, but it's often necessary if you're directly accessing nested properties in your template or computed properties. This can of course also be avoided by having something like <span v-if="person">{{ person.name}}</span>, but it also makes your markup more verbose.

I feel like the way beforeRouteEnter should work, is after you run your async operations and have your data ready, you should be able to somehow pass propsData during the vm creation. This would feel more natural to me, since data is coming from outside and these components would be guaranteed their data is already there when it renders.

I'd love to be able to do something like this:

export default {
  props: {
    person: {
      type: Object,
      required: true
    }
  },
  beforeRouteEnter(to, from, next) {
    ...
    next({
      person: {
        name: 'Carlos'
      }
    });
  }
}
@rhyek rhyek changed the title beforeRouteEnter's next callback called last beforeRouteEnter's next callback called last; should use propsData Dec 7, 2016
@rhyek
Copy link
Author

rhyek commented Dec 7, 2016

A couple of thoughts:

  • It could also be possible to pass a regular options object for further customization instead of just propsData.
  • This doesn't need to be a breaking change (if implemented). next could check whether the argument is a function or not. If not, treat as options.

@posva posva changed the title beforeRouteEnter's next callback called last; should use propsData Pass propsData in beforeRouteEnter's next callback and call it before mounting Dec 7, 2016
@naczu
Copy link

naczu commented Feb 11, 2017

is there any progress ?

@posva
Copy link
Member

posva commented Feb 11, 2017

No, right now the next callback waits for the next tick, that's why it's only called after the mounted hook

@psi-4ward
Copy link

@posva: The next callback gets called after mounted but if we pass an Object as argument there's no need to put it at the end of the event loop and could resolve the async loading problem:

beforeEnter(to, from, next) {
   axios.get().then(data => next({props: {data}));
}

BUT! We than we need also a beforeUpdate() to be able to react to $param changes

@psi-4ward
Copy link

Btw, this also works actually:

        props: function(to) {
          console.log('PROPS', to.meta.props);
          return to.meta.props;
        },
        beforeEnter(to, from, next) {
          console.log('before enter', to.meta);
          setTimeout(function() {
            to.meta.props = {
              id: to.params.id,
              test: "123"
            };
            next();
          },500);

@rhyek
Copy link
Author

rhyek commented Jun 28, 2017

@psi-4ward: Very interesting! It would kind of make route definitions rather verbose going with this approach, though. I feel like the general preference is in-component guards for this sort of thing.

Kind of off-topic, but I like Ember's approach where the route class has a model (params) hook where you return a Promise and after that resolves the controller is instantiated. If you configure it so, changing query params tied to route segments will also trigger the hook.

Returning promises allows for much cleaner code, IMO. Something like this would be cool:

export default {
  async model (to) {
    const { data } = await axios.get(`/api/items/${ to.params.id }`)
    return { item: data }
  },
  props: {
    item: {
      type: Object,
      required: true
    }
  }   

Edit: Any error raised inside model would be handled by router.onError.

@ooxif
Copy link

ooxif commented Jun 29, 2017

I wrote a tiny module which does things with SSR
https://www.npmjs.com/package/vue-router-guard
FYR

@posva posva removed the 2.x label Jul 10, 2018
@posva
Copy link
Member

posva commented Jul 10, 2018

As this is something that can be written in userland in a helper function and we don't want to overcomplicate apis and give even more solutions around data fetching, we will pass on this
Related #1923

@posva posva closed this as completed Jul 10, 2018
@kelp404

This comment has been minimized.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants