Vue Composition Reactive 属性不会在组件中更新
Vue Composition Reactive properties are not updating in components
我正在构建一个通知系统,它可以正常工作,但又不能正常工作。我有以下合成功能
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 组件来显示 Notification
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',
});
然后通知如预期显示这一切都发生在“auth”入口点内,上面都是打字稿。
现在,如果我转到第二个入口点(编辑器),并在现有的 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 组件中添加一个 watch,然后退出,第一个通知(上图)将使 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
我从您的代码中推断出,您的组件是紧密耦合的。我建议遵循更面向对象的方法,例如用户->数据->通知->已看到等等。这可能需要对数据库中的现有代码(和或)进行轻微重组。
我还建议您看看 firebase (FCM Firebase Cloud Messaging)。一个通知系统。 firebase 是一个 google 产品,可以相信他们的方法。(不是推广它,但他们实施通知系统的方式绝对可扩展)
但如果它是一个完全自主开发的应用程序并且不想依赖第三方,那么下一个最佳举措是使用“通知更改”方法。
粗略的概览是这样的
- 发生了 database/app 中的某些事件(需要通知用户)
- 追踪事件对受影响用户的影响[事件范围]
- 构建了一个通知对象[一些json文件]存储在数据库或普通json,例如notif.json
- 现在在用户激活后将其发送给用户。
您可以通过客户端的 setInterval() 函数检查它们是否处于活动状态。
一旦它们处于活动状态,请检查 notif.json,如果它有待处理的通知,则将其推送给用户并从文件或数据库中删除该条目。
经验法则就是不要在现有代码上浪费时间,如果它不工作,有时用不同的方法重写可以节省更多时间。
使用 GitHub 存储库中提供的代码,我在这部分之前添加了一些控制台日志记录:
window.notifications = reactive({
notifications: []
});
记录被调用了两次。一次来自 entry1.hash.bundle.js
一次来自 entry2.hash.bundle.js
.
我对 Webpack 的理解有限,但它似乎正在将这两个 entry-points 构建为 self-contained 并且不希望您 运行 它们都在同时翻页。
我原以为可以将所有通知内容提取到它自己的共享块中,有点像供应商捆绑包。也就是说,我不太清楚您为什么使用两个 entry-points 而不是两个块。我的理解是 entry-points 应该是 one-per-page 然后你用块把它们分开。
综上所述,有一个快速破解方法可以使其正常工作:
if (!window.notifications) {
window.notifications = reactive({
notifications: []
});
}
这确保了同一个数组被共享,无论它被共享多少次运行。
我要强调的是,我不提倡在生产代码中使用这种 hack。它只会进一步解决 Webpack 问题并污染进程中的全局命名空间。它确实有助于确认问题是什么。
我正在构建一个通知系统,它可以正常工作,但又不能正常工作。我有以下合成功能
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 组件来显示 Notification
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',
});
然后通知如预期显示
现在,如果我转到第二个入口点(编辑器),并在现有的 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 组件中添加一个 watch,然后退出,第一个通知(上图)将使 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
我从您的代码中推断出,您的组件是紧密耦合的。我建议遵循更面向对象的方法,例如用户->数据->通知->已看到等等。这可能需要对数据库中的现有代码(和或)进行轻微重组。
我还建议您看看 firebase (FCM Firebase Cloud Messaging)。一个通知系统。 firebase 是一个 google 产品,可以相信他们的方法。(不是推广它,但他们实施通知系统的方式绝对可扩展)
但如果它是一个完全自主开发的应用程序并且不想依赖第三方,那么下一个最佳举措是使用“通知更改”方法。
粗略的概览是这样的
- 发生了 database/app 中的某些事件(需要通知用户)
- 追踪事件对受影响用户的影响[事件范围]
- 构建了一个通知对象[一些json文件]存储在数据库或普通json,例如notif.json
- 现在在用户激活后将其发送给用户。
您可以通过客户端的 setInterval() 函数检查它们是否处于活动状态。 一旦它们处于活动状态,请检查 notif.json,如果它有待处理的通知,则将其推送给用户并从文件或数据库中删除该条目。
经验法则就是不要在现有代码上浪费时间,如果它不工作,有时用不同的方法重写可以节省更多时间。
使用 GitHub 存储库中提供的代码,我在这部分之前添加了一些控制台日志记录:
window.notifications = reactive({
notifications: []
});
记录被调用了两次。一次来自 entry1.hash.bundle.js
一次来自 entry2.hash.bundle.js
.
我对 Webpack 的理解有限,但它似乎正在将这两个 entry-points 构建为 self-contained 并且不希望您 运行 它们都在同时翻页。
我原以为可以将所有通知内容提取到它自己的共享块中,有点像供应商捆绑包。也就是说,我不太清楚您为什么使用两个 entry-points 而不是两个块。我的理解是 entry-points 应该是 one-per-page 然后你用块把它们分开。
综上所述,有一个快速破解方法可以使其正常工作:
if (!window.notifications) {
window.notifications = reactive({
notifications: []
});
}
这确保了同一个数组被共享,无论它被共享多少次运行。
我要强调的是,我不提倡在生产代码中使用这种 hack。它只会进一步解决 Webpack 问题并污染进程中的全局命名空间。它确实有助于确认问题是什么。