I have the following router configuration and would like that the id of the main.parent route is converted to an integer and then passed into the child components (given props: true) for all child components.
{
path: '/',
component: GrandparentComponent,
name: 'main',
children: [{
path: ':id',
component: ParentComponent,
name: 'main.parent',
props: route => {
return {
// parse URL id to int
id: parseInt(route.params.id, 10)
};
},
children: [{
path: 'details',
name: 'main.parent.child',
component: ChildComponent,
props: true,
children: [{
...
}]
}]
}]
}
However, it seems as if the route function is only really called once (when evaluating /:id) and not when /:id/details is evaluated. The relevant code in vue-router seems to confirm this.
const route = routeToDisplay.value;
const matchedRoute = matchedRouteRef.value;
const ViewComponent = matchedRoute && matchedRoute.components[props.name];
// we need the value at the time we render because when we unmount, we
// navigated to a different location so the value is different
const currentName = props.name;
if (!ViewComponent) {
return normalizeSlot(slots.default, { Component: ViewComponent, route });
}
// props from route configuration
const routePropsOption = matchedRoute.props[props.name];
const routeProps = routePropsOption
? routePropsOption === true
? route.params
: typeof routePropsOption === 'function'
? routePropsOption(route)
: routePropsOption
: null;
...
const component = h(ViewComponent, assign({}, routeProps, attrs, {
onVnodeUnmounted,
ref: viewRef,
}));
...
I wonder if anyone tried to solve the same problem and what they came up with a solution. Ideally, I’d like to avoid duplicating the props function for every child route.
Advertisement
Answer
There’s no such feature in Vue Router for passing props to child routes that way.
Instead, you could use provide/inject to effectively do this. The parent would provide the id property, and any descendant could inject it:
- In
ParentComponent.vue, usetoRefs()onpropsto get a reactiverefto theidprop. - Use
provide()to provide thatidto any children (including child routes). - Apply a
keyon<router-view>to ensure the view is re-rendered based on the uniqueid. - In
ChildComponent.vue, use theinjectprop to inject theidfrom step 2.
// ParentComponent.vue
<script>
/* Composition API */
import { provide, toRefs } from 'vue'
export default {
props: ['id'],
setup(props) {
const { id } = toRefs(props)
provide('id', id)
},
}
/* Options API */
import { toRefs } from 'vue'
export default {
props: ['id'],
provide() {
const { id } = toRefs(this.$props)
return { id }
},
}
</script>
<template>
<router-view :key="id" />
</template>
// ChildComponent.vue
<script>
export default {
inject: ['id'],
}
</script>
<template>
<h2>Detail {{ id }}</h2>
</template>