Dim*_*nis 7 javascript state-machine reactjs xstate
我已经广泛阅读了文档,但是,仍有一些部分不完全清楚,大多数与演员/服务有关
我对生成的演员生命周期的细节有点模糊。
.stop()
带有生成的演员的服务也会.stop()
是生成的演员还是他们被悬着?children
从服务本身内部访问生成的演员?(就像从一个动作内部)假设我有一台带有添加文件操作的机器。添加文件时,会spawn()
为其调用新文件,并将引用存储到context
. 现在,当机器完成不管它在做什么,我想重置context
并清除children
后,.stop()
荷兰国际集团各一台。
这里要完全具体地说明我是如何对实现上述行为的上传系统进行建模的。
在这个实现中,每当机器返回到idle
状态时,我都会重置context
并手动.stop()
调用每个生成的 actor。但是,actor 服务仍然在 中徘徊.children
,我无法从机器操作内部访问它们(将第三个参数添加meta
到resetContext
不会导致任何可以访问当前的children
)。
关于.stop()
ing 演员并清除children
和重置context
,理想情况下,我希望为每个演员单独采取行动,在idle
进入状态时运行,但是由于我似乎无法找到一种访问方式children
,因此通过一个动作完成所有操作这context
是我能想到的唯一解决方案。
另外,请注意,在官方示例中,当 todo 被删除时,其生成的 actor 不是.stop()
ed,这让我想知道这是疏忽还是有原因?
下面,为方便起见,是实现上传系统和文件的代码。完整的实现,其中还包括可视化器,可以在这里找到:
// upload system machine
const uploadSystemMachine = Machine(
{
id: 'upload-system',
initial: 'idle',
context: {
files: [],
successes: 0,
failures: 0,
cancellations: 0,
},
states: {
idle: {
entry: ['clearSpawnedActors', 'resetContext'],
on: {
OPEN: 'active',
},
},
active: {
initial: 'waitingForFiles',
states: {
waitingForFiles: {
on: {
CLOSE: {
target: '#upload-system.idle',
},
ADD: {
actions: 'addFile',
},
UPLOAD: {
target: 'pending',
cond: 'hasFiles',
},
},
},
pending: {
entry: 'startFileUploads',
on: {
'FILE.UPLOADED': {
actions: 'incrementSuccesses',
},
'FILE.FAILED': {
actions: 'incrementFailures',
},
'FILE.CANCELLED': {
actions: 'incrementCancellations',
},
CANCEL: {
actions: 'cancelFileUpload',
},
'': {
target: 'completed',
cond: 'allSettled',
},
},
},
completed: {
type: 'final',
on: {
CLOSE: '#upload-system.idle',
},
},
},
},
},
on: {
KILL: '.idle',
},
},
{
guards: {
hasFiles: context => {
return context.files.length > 0;
},
hasNoFiles: context => {
return context.files.length === 0;
},
allSettled: context => {
return (
context.files.length === context.successes + context.failures + context.cancellations
);
},
},
actions: {
startFileUploads: context => {
context.files.forEach(actor => {
actor.send('START');
});
},
addFile: assign({
files: (context, event) => {
const newValue = spawn(
fileMachine.withContext(event.target ? event.target.data : {}),
context.files.length
);
return [...context.files, newValue];
},
}),
resetContext: assign({
files: context => {
context.files.forEach(actor => {
console.log(actor);
actor.stop();
});
return [];
},
successes: 0,
failures: 0,
cancellations: 0,
}),
cancelFileUpload: (context, event) => {
const fileID = event.data.id;
for (let i = 0; i < context.files.length; i++) {
if (context.files[i].id === fileID) {
context.files[i].send('CANCEL');
break;
}
}
},
incrementSuccesses: assign({
successes: context => {
return context.successes + 1;
},
}),
incrementFailures: assign({
failures: context => {
return context.failures + 1;
},
}),
incrementCancellations: assign({
cancellations: context => {
return context.cancellations + 1;
},
}),
},
}
);
Run Code Online (Sandbox Code Playgroud)
// file machine
const fileMachine = Machine(
{
id: 'file',
initial: 'idle',
context: null,
states: {
idle: {
on: {
START: 'pending',
},
},
pending: {
invoke: {
id: 'upload',
src: 'upload',
},
on: {
RESOLVED: 'success',
REJECTED: 'failed',
CANCEL: 'cancelled',
},
},
success: {
type: 'final',
entry: [
() => {
console.log('%centering file success state', 'color: green');
},
sendParent('FILE.UPLOADED'),
],
},
failed: {
type: 'final',
entry: [
() => {
console.log('%centering file failed state', 'color: red');
},
sendParent('FILE.FAILED'),
],
},
cancelled: {
type: 'final',
entry: [
() => {
console.log('%centering file cancelled state', 'color: orange');
},
sendParent('FILE.CANCELLED'),
],
},
},
},
{
services: {
upload: (__context, event) => {
return callback => {
let cancelRequest;
let settled;
const req = new Promise((resolve, reject) => {
cancelRequest = reject;
console.log('Started uploading', event);
return setTimeout(() => {
const cond = Math.random() > 0.5;
if (cond) {
resolve();
} else {
reject();
}
}, Math.random() * 5000);
});
req
.then(() => {
settled = true;
console.log('%cFile uploaded successfully', 'color: green');
callback('RESOLVED');
})
.catch(() => {
settled = true;
console.log('%cFile failed to upload', 'color: red');
callback('REJECTED');
});
return () => {
if (!settled) {
console.log('canceling request');
cancelRequest();
}
};
};
},
},
}
);
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
413 次 |
最近记录: |