Маршрутизатор Vue не инициализирует дочерние компоненты - PullRequest
0 голосов
/ 04 апреля 2020

У меня странная проблема с vue-router.

У меня есть простое приложение CRUD для пользователей.

Он состоит из четырех различных представлений:

  1. Список пользователей и кнопка создания
  2. Создание представления с дочерним компонентом формы, который выбирает поля из API внутри создал ().
  3. Представление пользовательского шоу
  4. Представление пользовательского обновления с дочерним компонентом равной формы.

Если I go в первый раз на странице редактирования пользователя с идентификатором 1 все работает как брелок. Но если я go вернусь и нажму на другого пользователя и go на странице редактирования, он отобразит форму со значениями пользователя с идентификатором 1 и нового запроса ajax не будет.

Похоже, что компонент будет использоваться повторно. Я попытался задать дочерним компонентам формы разные значения :key, но безуспешно.

<router-view :key="$route.fullPath"></router-view>

Установка ключа в представлении маршрутизатора также не увенчалась успехом ...

Если я перезагрузлю браузер будет отображаться корректно

Вот пример в двух словах:

Мои маршруты:

import Index from "./views/Index";
import Show from "./views/Show";
import Edit from "./views/Edit";
import Create from "./views/Create";

export default [
    {
        path: '/admin/users',
        name: 'users.index',
        component: Index
    },
    {
        path: '/admin/users/create',
        name: 'users.create',
        component: Create
    },
    {
        path: '/admin/users/:id',
        name: 'users.show',
        component: Show,
        props: true
    },
    {
        path: '/admin/users/:id/edit',
        name: 'users.edit',
        component: Edit,
        props: true
    },
];

Редактировать компонент (Создать без идентификатора):

<template>
        <ResourceForm
            resource="user"
            :resource-id="id"
            @cancel="$router.push({name: 'users.index'})"
        />
</template>

<script>
    import ResourceForm from "../../../components/ResourceForm";

    export default {
        components: {ResourceForm},

        props: ['id'],
    }
</script>

Компонент ResourceForm:

<template>
    <form @submit.prevent="submitResourceForm">
        <component
            v-for="(field, index) in fields"
            :key="field.name + index"
            :ref="`${field.name}-field`"
            :is="field.component"
            :field="field"
            :validation-errors="getValidationErrors(field)"
        />
        <div class="mt-8 border-t border-gray-200 pt-5">
            <div class="flex justify-end">
                        <span class="inline-flex rounded-md shadow-sm">
                            <button type="button" @click="$emit('cancel')"
                                    class="py-2 px-4 border border-gray-300 rounded-md text-sm leading-5 font-medium text-gray-700 hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-50 active:text-gray-800 transition duration-150 ease-in-out">
                                {{this.cancelText}}
                            </button>
                        </span>
                <span class="ml-3 inline-flex rounded-md shadow-sm">
                            <button type="submit"
                                    class="btn">
                                {{this.submitText}}
                            </button>
                        </span>
            </div>
        </div>
    </form>
</template>
<script>
    import _ from 'lodash';
    import api from "../lib/api";
    import Form from "../lib/mixins/Form";

    export default {
        mixins: [Form],
        props: {
            resource: {
                type: String,
                required: true
            },
            resourceId: {
                required: false,
                default: null
            },
            cancelText: {
                type: String,
                default: 'Cancel'
            },
            submitText: {
                type: String,
                default: 'Submit'
            },
        },
        data() {
            return {
                fields: []
            }
        },
        watch: {
            '$route': function () {
                console.log('route changed');
                this.fetchResourceForm();
            }
        },
        created() {
            this.fetchResourceForm();
        },
        methods: {
            async fetchResourceForm() {
                let route;
                if (this.resourceId !== null) {
                    route = Cms.route('cms.api.forms.show', {
                        resource: this.resource,
                        id: this.resourceId
                    });
                } else {
                    route = Cms.route('cms.api.forms.new', {resource: this.resource});
                }

                const response = await api(route);
                this.fields = response.data.data.fields;
            },

            async submitResourceForm() {
                const formData = this.getFormData();

                try {
                    const foo = {
                        ...Cms.route('cms.api.forms.store', _.pickBy({
                            resource: this.resource,
                            id: this.resourceId
                        })),
                        data: formData
                    };
                    const response = await api(foo);

                    this.$emit('success', response.data.data);

                } catch (error) {
                    if (error.response.status === 422) {
                        this.validationErrors = error.response.data.errors;
                        Cms.flash('error', 'There are validation errors in the form.')
                    }
                }
            }
        }
    }
</script>

Метод Cms.route генерирует маршруты API и не имеет ничего общего с vue -router.

Ответы [ 4 ]

2 голосов
/ 04 апреля 2020

Наблюдайте за роутером от любого из родительских компонентов.

watch:{
  `$route`:function(route){
     if(route.name === 'users.create'){
       this.fetchData(route.params.id);
     }
   }
},
methods:{
   fetchData:function(id){
     // fetch your data corresponding to the id
     // save the response to store using `commit`.
     // this.$store.commit('SET_FIELDS',response.data.data.fields);
   }
}

Затем инициализируйте mutation и state в хранилище

const state = {
  fields:{}
}

const mutations = {
  SET_FIELDS:(state,value)=>state.fields = value;
}

Внутри компонента ResourceForm вы можете получить данные из store, используя computed method.

computed:{
  fields:function(){
    return this.$store.state.fields;
  }
}

Значение fields будет отображаться в реальном времени при изменении маршрута.

1 голос
/ 05 апреля 2020

Что вам нужно, это В компонентных средствах защиты , поскольку эти методы защиты доступны в компонентах, поскольку вы передали импортированное представление непосредственно в vue-router:

    {
        path: '/admin/users',
        name: 'users.index',
        component: Index // <-- makes Component Guards available in './views/Index.vue'
    },

Замените:

created() {
  this.fetchResourceForm();
}

с:


  // Fires if you are already on a DYNAMIC route when a uri parameter like :id changes
  // This will for example run if you navigate from `/admin/users/123` to `/admin/users/456`
  beforeRouteUpdate(to, from, next) {
    this.fetchResourceForm();
    next()
  },

  // Fires if you switch between different router entries.
  // When you navigate from `/something` to `/another-path
  beforeRouteEnter(to, from, next) {
    this.fetchResourceForm();
    next()
  },

Тем не менее, если вы выбираете данные внутри компонента, который находится в представлении маршрутизатора, тогда потребуется watch, как предлагали другие, но почему бы не просто передать данные как prop вместо?

1 голос
/ 04 апреля 2020

Я думаю, вы можете перевести пользователя в состояние vuex и использовать это состояние в обоих компонентах. Или, может быть, запустить запрос в beforeEnter hook

0 голосов
/ 04 апреля 2020

Я нашел проблему. Это относится не к этой функциональности, а к компоненту, который генерирует маршруты API. Решение @ Rijo sh работает, если кто-то сталкивается с этой проблемой в vue -router.

...