私はドキュメントを広範囲に読みましたが、まだ完全に明確ではない部分がいくつかあり、ほとんどはアクター/サービスに関係しています
スポーンされたアクターのライフサイクルの詳細については、少し曖昧です。
.stop()
スポーンされたアクターでサービスを呼び出すと、スポーンされたアクターも呼び出され.stop()
ますか、それともハングしたままになりますか?- スポーンされたアクターをマシンからクリアするにはどうすればよいですか?
children
サービス自体の内部からスポーンされたアクターにアクセスする方法はありますか? (アクション内からのように)
ファイルを追加するためのアクションを備えたマシンがあるとします。ファイルが追加されると、それに対して newspawn()
が呼び出され、参照がcontext
. さて、マシンが何をしていても終了したら、それぞれをリセットしてクリアしたいと思いcontext
ます。children
.stop()
ここで完全に具体的に言うと、上記の動作を実装するアップロード システムをどのようにモデル化したかということです。
この実装では、マシンがその状態に戻るたびに、スポーンされた各アクターを手動でidle
リセットして実行しています。ただし、アクター サービスはまだ にぶら下がっていて、マシン アクション内からアクセスすることはできません (3 番目のパラメーターを に追加しても、現在の にアクセスすることはできません)。context
.stop()
.children
meta
resetContext
children
.stop()
アクターの ing と のクリアchildren
と のリセットに関してはcontext
、理想的には状態が入力されたときに実行されるように、それぞれに個別のアクションが必要idle
ですが、 にアクセスする方法が見つからないように見えるため、children
すべてを 1 つのアクションで実行します。これcontext
が私が考えることができる唯一の解決策です。
また、todo が削除されたときの公式の例では、スポーンされたアクターが.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;
},
}),
},
}
);
// 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();
}
};
};
},
},
}
);