Реактивные свойства Vue Composition не обновляются в компонентах

Я создаю систему уведомлений, и она вроде как работает, но вроде нет. У меня есть следующая функция композиции

const data = reactive({
    notifications: []
});
let notificationKey = 0;

export const useNotification = () => {
    const visibleNotifications = computed(() => {
        return data.notifications.slice().reverse();
    });

    const add = (notification: INotification) => {
        notification.key  = notificationKey++;
        notification.type = notification.type ?? 'success';

        notification.icon      = iconObject[notification.type];
        notification.iconColor = iconColorObject[notification.type];
        data.notifications.push(notification);

        notificationTimer[notification.key] = new Timer(() => {
            remove(notification.key);
        }, notificationTimeout);
    };

    const remove = (notificationKey: number) => {
        const notificationIndex = data.notifications.findIndex(notification => notification?.key === notificationKey);
        if (notificationTimer[notificationKey] !== undefined) {
            notificationTimer[notificationKey].stop();
        }
        if (notificationIndex > -1) {
            data.notifications.splice(notificationIndex, 1);
        }
    };

    const click = (notification: INotification) => {
       /// ... click code 
    };

    return {
        visibleNotifications,
        add,
        remove,
        click
    };
};

Это работает (немного упрощено). Теперь у меня есть две точки входа в Webpack. В одной точке входа (auth) у меня есть следующий код для загрузки компонента Vue для отображения уведомления

 Promise.all([
    import(/* webpackChunkName: "Vue"*/ 'vue'),
    import(/* webpackChunkName: "@vue/composition-api"*/ '@vue/composition-api'),
    import(/* webpackChunkName: "Notifications"*/'components/Notifications.vue')
]).then((
    [
        { default: Vue },
        { default: VueCompositionAPI },
        { default: Notifications },
    ]) => {
    Vue.use(VueCompositionAPI);

    new Vue({
        render: h => h(Notifications)
    }).$mount('.notification-outer);
});

Теперь все работает, и я добавляю туда следующий код

import { useNotification } from 'modules/compositionFunctions/notifications';
useNotification().add({
    title  : 'Error',
    message: 'This is an error notification',
    type   : 'error',
});

Затем уведомление отображается как ожидалось  notification image Все это происходит внутри точки входа аутентификации, и все это машинописный текст.

Теперь, если я перейду ко второй точке входа (редактору) и в существующем файле JS введите следующий код

import(/* webpackChunkName: "useNotification"*/ 'modules/compositionFunctions/notifications').then(({ useNotification }) => {
    useNotification().add({
        title     : 'Block Deleted',
        message   : 'The block has been deleted',
        buttonText: 'Undo',
        buttonFunction () {
            undoDelete();
        }
    });
});

Тогда это работает, и под этим я подразумеваю, что работает весь код из функции useNotification. Метод добавления добавит его (если я выйду из консоли с реактивным свойством), и через 15000 мс произойдет удаление методов, и я могу добавить журналы, чтобы показать это. ОДНАКО компонент Vue никогда не видит этого изменения. Если я добавлю часы в компонент Vue и выйду из системы по мере продвижения, первое уведомление (изображение выше) внесет JS-журнал в консоль, однако при добавлении его из точки входа редактора он ничего не сделает.

Компонент Vue JS

import { useNotification } from 'modules/compositionFunctions/notifications';
import { defineComponent } from '@vue/composition-api';

export default defineComponent({
    name : 'Notifications',
    setup () {
        const { visibleNotifications, remove, click: notificationClick } = useNotification();

        return {
            visibleNotifications,
            remove,
            notificationClick,
        };
    },
    watch: {
        visibleNotifications: (v) => {
            console.log(v);
        }
    }
});

ПОЖАЛУЙСТА, кто-нибудь, подскажите, что они могут помочь? Это начинает делать мою голову в ...

TIA


person LeeR    schedule 31.08.2020    source источник
comment
Можете ли вы предоставить демоверсию вcodeandbox ??   -  person tuhin47    schedule 02.09.2020
comment
Можете ли вы показать код метода remove?   -  person Krzysztof Kaczyński    schedule 02.09.2020
comment
@ tuhin47 - Я так не ДУМАЮ? Это полная установка Webpack с несколькими конечными точками, что, по моему мнению, невозможно в Codepen.   -  person LeeR    schedule 02.09.2020
comment
@ KrzysztofKaczyński Я не думаю, что проблема заключается в методе удаления, поскольку в data contains есть все, когда я выхожу из системы. Все равно добавил это в приведенное выше   -  person LeeR    schedule 02.09.2020
comment
Не могли бы вы подтвердить, что компонент Notifications действительно где-то отображается, когда вы используете точку входа редактора? Кроме того, не могли бы вы попробовать поместить ведение журнала консоли прямо в верхнюю часть notifications.ts, чтобы подтвердить, что файл загружается только один раз (чтобы подтвердить, что data.notifications уникален). Предполагая, что ни одна из этих проблем не является проблемой, не могли бы вы разместить урезанную, собираемую, работающую версию вашего приложения на GitHub, чтобы мы могли попробовать ее сами?   -  person skirtle    schedule 03.09.2020
comment
Я попробую утром и отправлю результаты обратно   -  person LeeR    schedule 03.09.2020
comment
@LeeR Думаю, может быть проблема с методом удаления. Можете ли вы попробовать мой ответ и сообщить, работает ли он?   -  person Krzysztof Kaczyński    schedule 03.09.2020
comment
Я обновил свой код выше, как теперь он у меня есть. Я больше не использую клавишу visible, чтобы определять, показывать ли уведомление или нет. Я просто добавляю или удаляю уведомление из массива, чтобы обеспечить реактивность   -  person LeeR    schedule 04.09.2020
comment
@skirtle. Репо найдено здесь: github.com/leereichardt/vue-composition-entry-points. Если вы запустите npm ci, затем npm start, а затем откроете dist/index.html в браузере, все будет в порядке. Интересно, что в этом случае у меня есть код как в entry1, так и в entry2, и иногда 1 будет работать, а 2 нет, или 2 будет работать, а 1 нет, но я не могу найти причину того, что происходит   -  person LeeR    schedule 04.09.2020


Ответы (2)


Используя код, представленный в репозитории GitHub, я добавил несколько консольных журналов непосредственно перед этой частью:

window.notifications = reactive({
   notifications: []
});

Регистрация вызывалась дважды. Один раз из entry1.hash.bundle.js и один раз из entry2.hash.bundle.js.

Мое понимание Webpack ограничено, но, похоже, он строит эти две точки входа так, чтобы они были самодостаточными, и не ожидает, что вы запустите их обе на странице одновременно.

Я бы подумал, что можно будет извлечь все материалы уведомлений в свой собственный общий блок, немного похожий на пакет поставщиков. Тем не менее, я не совсем понимаю, почему вы используете две точки входа, а не два фрагмента. Насколько я понимаю, точки входа должны быть по одной на страницу, а затем вы разделяете их на куски.

С учетом всего сказанного, есть быстрый способ заставить его работать:

if (!window.notifications) {
    window.notifications = reactive({
        notifications: []
    });
}

Это гарантирует, что один и тот же массив будет совместно использоваться независимо от того, сколько раз он запускается.

Я должен подчеркнуть, что я не защищаю использование такого взлома в производственном коде. Это просто устраняет проблемы Webpack в дальнейшем и загрязняет глобальное пространство имен в процессе. Тем не менее, это помогает подтвердить, в чем проблема.

person skirtle    schedule 04.09.2020
comment
Причина, по которой мы используем две точки входа, заключается в том, что у нас есть различные части всего нашего приложения. Раньше это были отдельные файлы для загрузки, когда они находились в редакторе / авторизации / выходе из системы и т. Д. Моя цель - в конечном итоге использовать для этого чанки, но мы перенесли Webpack в устаревшую систему, и, к сожалению, это нужно делать именно так. НО! Это решило проблему, поэтому теперь нужно выяснить, как заставить его загружать фрагмент только один раз, чтобы не перезаписывать файлы! Спасибо большое! - person LeeR; 04.09.2020

из вашего кода я делаю вывод, что ваши компоненты тесно связаны. и я предлагаю следовать более объектно-ориентированному подходу, например, ›данные-› уведомление- ›просмотрены пользователем и так далее. для этого может потребоваться небольшая реструктуризация вашего существующего кода (и или) в базе данных.

Я также предлагаю вам взглянуть на firebase (FCM Firebase Cloud Messaging). система уведомлений. firebase - продукт Google, может доверять их методологии. (не продвигая ее, но способ, которым они реализуют систему уведомлений, абсолютно масштабируем)

но если это полностью самостоятельно разработанное приложение, которое не хочет полагаться на стороннюю организацию, то следующий лучший шаг - использовать метод уведомления об изменении.

приблизительный обзор будет таким.

  • какое-то событие в базе данных / приложении (о котором должен быть уведомлен пользователь) происходит
  • отслеживать, что событие делает с затронутыми пользователями [объем события]
  • создал объект уведомления [некоторый файл json], хранящийся в базе данных или простой json, например notif.json
  • теперь отправьте это пользователю, когда он станет активным.

вы можете проверить, активны они или нет, с помощью функции setInterval () на стороне клиента. и как только они станут активными, проверьте notif.json, и если у него есть ожидающее уведомление, отправьте его пользователю и удалите эту запись из файла или БД.

Эмпирическое правило - не тратить время на существующий код, если он не работает, иногда переписывание с использованием другого подхода экономит больше времени.

person nikhil swami    schedule 03.09.2020
comment
Это полностью самостоятельно разработанное приложение, в котором мы не хотим слишком полагаться на сторонние библиотеки для этого, а также просто для пояснения, уведомления - это не столько push-уведомления, которые мы доставляем и ждем, чтобы их увидели, но и больше в режиме реального времени. уведомления, которые отображаются при взаимодействии с самим веб-приложением. - person LeeR; 03.09.2020
comment
о, ха-ха, неважно, я собирался поделиться некоторыми идеями и тем, как я лично их воплощаю. похоже, что мой ответ не добавил ценности. : -E - person nikhil swami; 05.09.2020