【发布时间】:2020-09-26 21:18:14
【问题描述】:
我有这段代码来跟踪位置变量,上游事件是键盘侦听器。我想发出“开始”位置,以便在进行任何真正的按键操作之前将播放器绘制在屏幕上,所以我构建了这个 observable,它以 noop 开始,以便在没有任何移动的情况下发出开始位置:
$keyboardEvent.pipe(
startWith(
{
key: Key.Noop,
keys: [Key.Noop],
keyStroke: KeyStroke.Down,
},
{ key: Key.Noop, keys: [], keyStroke: KeyStroke.Up }
),
tap(({ keys }) => (keysRef.current = keys)),
switchMap(() => (keysRef.current.length > 0 ? $animationEvent : EMPTY)),
map(() => {
if (keysRef.current.length > 0) {
playerPosition.current = updatePlayerPosition(keysRef.current);
playerRotation.current = updatePlayerRotation(keysRef.current);
}
playerMovementState.current =
keysRef.current.length > 0 ? "active" : "idle";
return {
position: playerPosition.current,
rotation: playerRotation.current,
state: playerMovementState.current,
};
})
)
问题似乎是 switchMap 操作符在第二个启动事件通过管道后立即取消 $animationEvent,这似乎发生在第一个事件可以发送给订阅者之前。当我在 switchMap 之前点击事件时,这是输出:
{key: "", keys: Array(1), keyStroke: "Down"}
{key: "", keys: Array(0), keyStroke: "Up"}
当我在 switchMap 之后点击时,我没有得到任何结果,即使我知道 $animationEvent 在第一个事件通过管道后返回。
有人可以帮忙解释一下这种行为吗?是否有任何解决方法?我宁愿不必使用一些缓冲的 observable,它的窗口足够大,足以让事件发生在下游,因为这似乎无法长期维护,而且我不应该一开始就这样做。
【问题讨论】:
-
您好!如果它有助于直觉,我的想法是,当 switchMap 接收到一个新值时,它会将其作为一个信号,即基于先前值所做的任何工作都应该被废弃,并切换到处理新值。至于解决方法,它只取决于您需要什么行为 - 例如,如果用户的按键在动画进行时不应该做任何事情,只需将 switchMap 替换为排气映射。
-
感谢您的快速回复!我正在寻找的是在订阅主 observable 时发出一个起始值。在该起始值之后,键盘按下将启动一个动画循环,该循环将把玩家拉到与按键相关的位置,并且在空闲之后,observable 将完成(也就是切换到 EMPTY 以便 RAF 停止处理)。如果我将 startWith 移到 switch map 之后,它只会在每次按键后重置位置,这也是不好的行为。
-
哦,我想我明白了!我会回复一个答案以获得更多空间,稍后会发布。
标签: javascript reactjs events rxjs