Description
I'm creating an issue with my comments in #1126 since they never got any attention:
@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 props
very nicely when trying to solve the problem of passing data from a route to a component in the most correct way. In my own issue, #992, I propose the option of passing props
to a not-yet-created component during beforeRouteEnter
. Currently, this hook only allows you to set data
properties after the component has been created (next(vm => vm.someProp = resolvedData)
)
props
are a way of providing bits of data to a component from an external source traditionally from a parent component or, less frequently, with propsData
. Now, thanks to #973, it is also possible from a route definition. In all these cases, the data is available before a component is initialized.
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 props
function in the route definition to optionally return a promise which, when resolved with the incoming data, allows us to continue with component creation passing along the data as props
.
{{ obj && obj.property }}
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 props
as required, you know that data is there at render time. Same should apply for API data.
<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:
- It is boilerplate I would not like to see repeated over and over in my application
- It doesn't work with
props
so I can't have validation - It doesn't allow you to have things such as default handlers for API errors.
- No separation of concerns. My component should always just assume the data is there and all handling of errors or loading animations should be done in a more appropriate and probably centralized place.
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 props
and either handle any errors or pass the resolved data to the component. Only difference is this time around the component is already initialized. Same thing that happens when a child component's props
are modified in the parent component.
I realize this provides similar functionality to beforeRouteEnter
and beforeRouteUpdate
. Main differences are:
- Using
props
vsdata
(data available before or after component initialization) - No need for two hooks, just one
props
function - Possibility of having global HTTP error handlers