【发布时间】:2021-12-13 09:36:49
【问题描述】:
我正在制作一个基于套接字连接的简单应用程序。基本上,一个用户决定其他用户可以看到什么。功能之一是为其他用户启动计时器。因此,有一个 Timer 组件具有 timerState 变量和 startTimer 函数。当用户连接到套接字时,定时器组件与整个用户视图一起呈现。对传入事件“计时器已启动”做出反应很容易,而且效果很好。当计时器已经启动并且用户刷新他的浏览器(或者只是延迟连接,当计时器已经设置时)时,问题就开始了。 设置定时器的信息存储在数据对象中,在初始连接到套接字后作为欢迎事件发送给用户。
为简化起见,用户视图的组成如下:
{#if !isDataComplete}
<WaitingComponent>
{:else}
<Timer bind:{tools}>
{/if}
Tools 是一个包含一些方法的对象,主要是 startTimer 方法。
因此,在连接后,用户接收到数据对象,它将 wiev 从等待切换到应用程序 wiev(这里:计时器,最初为空,但已渲染)。如果有一个 timer 属性,这意味着一个 timer 已经设置并且应该调用 startTimer 方法。但是, startTimer 方法还不能访问,因为脚本比渲染快,而且 Timer 组件还没有。数据实际上并没有被获取,它带有来自套接字的“欢迎”事件,所以等待数据并不能解决问题,我需要等待组件渲染。
let isDataComplete = false;
socket.on('welcome', async (incomingData) => {
isDataComplete = incomingData.isAppReady; // triggers switch view if true
await timeout(500); // my "lame solution" (timeout is just setTimeout wrapped in Promise to make that awaitable)
if (data.timer) {
const currTime = Date.now();
if (currTime < data.timer.start + data.timer.duration) {
const remainingTime = Math.floor(
(data.timer.start + data.timer.duration - currTime) /
1000
);
tools.startTimer(remainingTime, true);
}
}
});
如您所见:我通过在脚本中添加等待 setTimeout 500 毫秒(在调用 startTimer 之前)“解决”了这个问题——成功了,组件管理渲染并且方法已经可以访问。但不知何故,我觉得这是一个蹩脚的解决方案,所以也许有人可以通过其他方式提供帮助?
我可以简单地将计时器组件放在 if 块之外,使其在接收数据之前就呈现出来,但由于视图结构,这并不是一个好主意。
我试图将 setTimer 方法存储在其他地方并导入它,但它会导致从外部管理计时器状态时遇到一些困难。但这当然是一种有效的尝试方式。
非常感谢! 普热梅克
【问题讨论】:
-
无需深入了解您的场景...也许生命周期可能有用svelte.dev/tutorial/onmount(例如,使用 onDestroy() 删除已启动的计时器)
标签: svelte svelte-3 svelte-component