Scopes also work across asynchronous calls in that a method called asynchronously can call the `use' method to access values from the Scope.
final keyAge = ScopeKey<int>('age');
final one = await (Scope()
..value<int>(keyAge, 18))
.run<Future<int>>(() async {
/// setup up a 1 second delay and call `use` within
/// a future.
final delayedvalue =
Future<int>.delayed(const Duration(seconds: 1), () => use(keyAge));
return delayedvalue;
expect(one, equals(18));
The Future MUST also be created within the Scope.
Just because a method runs concurrently to a Scope does not mean the method has access to the Scope.
Just because another async method runs during the scope's existence does not mean it has access to the Scope. It must be called from a method within the Scope's call stack.
Scope -> run -> a -> b -> c
Where -> means calls; a, b and c have access to the the Scope.
main -> d -> f -> c
Even if these methods are run asynchronously whilst the Scope exists they will not have access to the Scope as they were not called from the Scope's run method.

Calling async methods

You will often need the Scope's run method to make async calls and have the call wait until the run completes.
This is simple to do:
/// May sync call
..value<bool>(tenatId, 10)
..value<bool>(bypassTenantKey, true) {
/// Make async call.
await (Scope()
..value<bool>(tenatId, 10)
..value<bool>(bypassTenantKey, true)
.run(() async {
await action();
There are five key changes required to make the async call:
  • add an await before the call to Scope()
  • add async after the `run(()`
  • wrap the Scope and value builder calls in parenthesis
  • change to .run
  • add `await` before the call to action
Its critical that you note step 3.
The notation tells dart to call run but still return Scope. It is the run method that is async so we need to ensure that the result of the expression is the result of run not a Scope.
Copy link