-
-
Notifications
You must be signed in to change notification settings - Fork 5.1k
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
[FR] - Pass a promise to new props function #1126
Comments
We can already do this with beforeRouteEnter (to, from, next) {
getPost(to.params.id, (err, post) => {
if (err) {
// display some global error message
next(false)
} else {
next(vm => {
vm.post = post
})
}
})
}, Props are meant to pass data that is relative to the route to its component in a more native way so you don't have to use |
@posva yes, great, but props can be set post factum, after the vm initialized. |
@posva This would delay route rendering until the call returns data, which is exactly why I'd like to use props. An app feels much more responsive when the route changes and the data comes after, even if the route is an empty shell for the moment until the data is loaded. What I've realized is, that in my understanding, the props should also be reinitialized when a dynamic route changes its params or query. So still, it's maybe not the best idea to use this approach... |
If your view relies on some specific data being ready, you can move that part to a component and display when the view is ready. That way you clearly separate the logic of fetching and displaying @nirazul You don't need any hook to achieve that: https://router.vuejs.org/en/advanced/data-fetching.html |
@posva sorry for insistent tries to be heard... |
No worries 🙂 . That data should not be fetched by the components but instead fetched at a view level or using something like vuex |
yes, already doing this, as described in #1123 |
@posva // old
{
watch: {
// call again the method if the route changes
'$route': 'fetchData'
}
}
/* can be replaced with */
// new
{
beforeRouteUpdate (to, from, next) {
this.fetchData();
}
} @sleewoo export default {
data() {
return {
// nobody likes undefined properties
routeData: {}
};
},
methods: {
receiveFetched(fetched) {
this.routeData = this.$set(this, 'routeData', fetched);
}
},
beforeRouteEnter(to, from, next) {
const Fetched = to.meta.fetch();
next(vm => Fetched.then(vm.receiveFetched));
},
beforeRouteUpdate(to, from, next) {
const Fetched = to.meta.fetch();
Fetched.then(this.receiveFetched);
next();
}
}; Using this in a route is as easy as... : import routeMixin from 'path/to/routeMixin';
export default {
mixins: [routeMixin]
} When switching routes, the fetch will be executed automatically and stored within the You can combine this with a vuex cache store that keeps the responses via the fetch url and returns data from storage if available. |
@nirazul good approach, but after #973 this can be refined to a native solution. Compare to this: props: {
env: { type: Object, required: true }
}
beforeRouteEnter(to, from, next) {
to.meta.fetch().then((env) => next( { props: { env } } ))
} Pros:
Cons:
Your method is even more attractive to me, but returning promises is sort of hairy, is not it? :) routes: [
props: [
'static',
'dynamic'
],
{
path: '/dynamic',
component: Hello,
props: { static: 'foo' },
asnycProps(route, resolve) {
route.meta.fetch().then((dynamic) => resolve( { props: { dynamic } } ))
}
}
] and we get the view initialized with both static and dynamic props. though not sure how to proceed when route's params/query changes :) |
@sleewoo I'll close this ticket, as all intentions are clear now and there's no intention to implement. Also, there's no clear path what to do on params/query change. |
@posva, @nirazul although your suggestions provide a solution, I think there is another way. I like #973 very much because it leverages the use of
Data coming over the wire is also an external source and, in my opinion and for consistency's sake, should be handled in a similar fashion. The most obvious way to do it would be to allow the
This is verbose and is a pattern I would like to not have to include in all my routable components. When you're designing a component that is meant to be called from a parent component, you don't have to do that because if you configure your <Spinner v-if="!obj"/>
<div v-else>
{{ obj.property }}
</div> This is essentially what the data fetching section Fetching after navigation suggests and that's fine. This is how @nirazul prefers it, too. IMO:
I would like to be able to do something like this: // router.js
const router = new VueRouter({
routes: [
{
path: '/people/:id',
component: require('components/Person'),
props(to) {
return axios
.get(`/api/people/${ to.params.id }`)
.then(response => response.data)
}
}
],
errorHandlers: {
301: (to, from, next, error) {
next(error.response.headers.Location)
},
400: require('components/BadRequest'),
401: () => {
store.commit('logout') // store will navigate to home route or whatever
},
404: require('components/NotFound')
// 400 and 404 will cause Vue to render their respective components
// while optionally having already navigated to the new URL
}
})
router.beforeEach(() => {
store.commit('loading', true) // shows loading spinner
})
router.afterEach(() => {
store.commit('loading', false) // hides loading spinner
}) <!-- Person.vue -->
<template>
<div>
{{ person.name }} <!-- no error -->
</div>
</template>
<script>
export default {
props: {
person: {
type: Object,
required: true
}
}
}
</script> <!-- BadRequest.vue -->
<template>
<div>
<h1>Oops!</h1>
<p>{{ error.response.data.message }}</p>
</div>
</template>
<script>
export default {
props: {
error: { // from promise catch()
type: Object,
required: true
}
}
}
</script> Another concern I've seen here is what happens when a route param changes. IMO, you just start over from the moment you call |
I realize this provides similar functionality to
|
I really like the new possibility to pass props to route components, thanks for implementing it!
As this would be a nice opportunity to use a props method as an API data fetcher, I'm intersted in passing a Promise either directly or returning one by this function.
I imagine something like this:
The text was updated successfully, but these errors were encountered: