8

私はドキュメントを広範囲に読みましたが、まだ完全に明確ではない部分がいくつかあり、ほとんどはアクター/サービスに関係しています

スポーンされたアクターのライフサイクルの詳細については、少し曖昧です。

  • .stop()スポーンされたアクターでサービスを呼び出すと、スポーンされたアクターも呼び出され.stop()ますか、それともハングしたままになりますか?
  • スポーンされたアクターをマシンからクリアするにはどうすればよいですか? childrenサービス自体の内部からスポーンされたアクターにアクセスする方法はありますか? (アクション内からのように)

ファイルを追加するためのアクションを備えたマシンがあるとします。ファイルが追加されると、それに対して newspawn()が呼び出され、参照がcontext. さて、マシンが何をしていても終了したら、それぞれをリセットしてクリアしたいと思いcontextます。children.stop()

ここで完全に具体的に言うと、上記の動作を実装するアップロード システムをどのようにモデル化したかということです。

この実装では、マシンがその状態に戻るたびに、スポーンされた各アクターを手動でidleリセットして実行しています。ただし、アクター サービスはまだ にぶら下がっていて、マシン アクション内からアクセスすることはできません (3 番目のパラメーターを に追加しても、現在の にアクセスすることはできません)。context.stop().childrenmetaresetContextchildren

.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();
            }
          };
        };
      },
    },
  }
);
4

0 に答える 0