Skip to content

Invoke futures

Ricardo Canastro edited this page Jun 29, 2022 · 2 revisions

The invoke element is used to create an instance of an external service. At the moment automata's invoke is tightly coupled with asynchronous workflows, whenever a state with a invoke is entered, it's src callback is called and awaited. If the future resolves it calls onDone, otherwise it calls onError.

final machine = StateMachine.create(
  (g) => g
    ..initial<_Idle>()
    ..state<_Idle>(
      builder: (b) => b..on<_OnFetch, _Loading>(),
    )
    ..state<_Loading>(
      builder: (b) => b
        ..invoke<List<_RedditEntry>>(
          builder: (b) => b
            ..id('fetchTopics')
            ..src((_) => _fetchReddit(shouldFail: !hasFetchedOnce))
            ..onDone<_Success, List<_RedditEntry>>(
              actions: [(event) {}],
            )
            ..onError<_Failure>(
              actions: [(event) {}],
            ),
        ),
    )
    ..state<_Success>(type: StateNodeType.terminal)
    ..state<_Failure>(
      builder: (b) => b..on<_OnRetry, _Loading>(),
    ),
);

Conditional OnDone callbacks

To account for the various outcomes of the invoked function, multiple onDone can be defined, each with a condition to specify the pertinent outcome, and a target state, Automata will pick the first onDone that either does not have a condition, or the condition evaluates to true.

StateMachine.create(
  (g) => g
    ..initial<_Idle>()
    ..state<_Idle>(
      builder: (b) => b..on<_OnFetch, _Loading>(),
    )
    ..state<_Loading>(
      builder: (b) => b
        ..invoke<_TestMockResult>(
          builder: (b) => b
            ..id('fetchUser')
            ..src(invokeSrcCallback)

            // onDone which will be entered if response value is `true`
            ..onDone<_Success, _TestMockResult>(
              condition: ((event) => event.data.value == expectedResult),
              actions: [() {...}],
            )

            // onDone which will be entered if response value is `false`
            ..onDone<_SuccessB, _TestMockResult>(
              condition: ((event) => event.data.value == expectedResultB),
              actions: [() {...}],
            )
            ..onError<_Failure>(
              actions: [() {...}],
            ),
        ),
    )
    ..state<_Success>(type: StateNodeType.terminal)
    ..state<_SuccessB>(type: StateNodeType.terminal)
    ..state<_Failure>(
      builder: (b) => b..on<_OnRetry, _Loading>(),
    ),
);
Clone this wiki locally