Home > front end >  How to inherit props from parent route with vue-router
How to inherit props from parent route with vue-router

Time:10-08

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.

CodePudding user response:

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:

  1. In ParentComponent.vue, use toRefs() on props to get a reactive ref to the id prop.
  2. Use provide() to provide that id to any children (including child routes).
  3. Apply a key on <router-view> to ensure the view is re-rendered based on the unique id.
  4. In ChildComponent.vue, use the inject prop to inject the id from 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>

Composition API demo

Options API demo

  • Related