有点小众的问题,但我知道问题是什么,所以希望这里有人可以帮助我。这是 Observable/RXFire 问题,而不是 xstate 问题。
我有这台机器调用一个可观察的:
export const tribeMachine = Machine(
{
id: "council",
initial: "init",
context: {},
states: {
init: {
invoke: {
id: "gettribes",
src: () =>
collectionData(database.collection("tribes")).pipe(
concatAll(),
map(x => ({ type: "STORE", x }))
),
onDone: "loaded"
},
on: {
STORE: {
actions: "storetribes"
},
CANCEL: "loaded"
}
},
loaded: {
entry: () => console.log("loaded")
},
error: {
entry: () => console.log("error")
}
}
},
{
actions: {
storetribes: (context, event) => console.log("hello")
}
}
);
它应该工作的方式是机器在加载时调用 observable,然后一旦 obs 完成发出其值并调用 complete(),invoke.onDone 被调用并且机器转换到“加载”状态。
当我使用通过 complete() 调用创建的普通 observable 时,或者当我将 take(#) 添加到 .pipe() 的末尾时,转换工作。
但由于某种原因,来自 RXFire 的 collectionData() 的可观察数据没有发出“完整”信号……机器就坐在那里。
我尝试在末尾添加一个 empty() 并 concat() 对 observables 添加一个完整的信号到管道的末尾......但后来我发现 empty() 已被弃用并且它没有似乎无论如何都可以工作。
有一段时间我的头撞在墙上。任何帮助表示赞赏。
编辑:
解决方案:
我误解了 collectionData() 的目的。它是一个监听器,所以它不应该完成。我在圆孔里放了一个方钉。解决方案是重构 xstate 机器,所以我根本不需要调用 onDone。
尽管如此,还是感谢您的回答。
EDIT2:让它工作。
take(1) 可以在 concatAll() 之前调用。我想如果你先调用它,它会结束流,但事实并非如此。管道中的其他运算符仍然适用。所以我采取(1) 来获取单个数组,使用 concatAll() 将数组展平为单个对象的流,然后将该数据映射到触发 STORE 操作的新对象。然后 store 操作将数据设置为机器的上下文。
export const tribeMachine = Machine({
id: 'council',
initial: 'init',
context: {
tribes: {},
markers: []
},
states: {
init: {
invoke: {
id: 'gettribes',
src: () => collectionData(database.collection('tribes')).pipe(
take(1),
concatAll(),
map(value => ({ type: 'TRIBESTORE', value })),
),
onDone: 'loaded'
},
on: {
TRIBESTORE: {
actions: ['storetribes', 'logtribes']
},
CANCEL: 'loaded'
}
},
loaded: {
},
error: {
}
}
},
{
actions: {
storetribes: assign((context, event) => {
return {
tribes: {
...context.tribes,
[event.value.id]: event.value
},
markers: [
...context.markers,
{
lat: event.value.lat,
lng: event.value.lng,
title: event.value.tribeName
}
]
}
})
}
}
)
感谢大家的帮助!