# run_once
An extremely simple library for running 'things' exactly once. No matter how many times that 'thing' is called.

## How does it work?

Well it's very simple. We basically use the `StackTrace.current` and carefully use this to keep record on when a function has been called. It means that the call stack is basically used as a unique identifier for when and where a function has been called.

## Rationale

This library could be considered an anti-pattern in itself and a little exercise, but imagine a Flutter `StatefulWidget` with its `build` that you cannot rely on being called only when you yourself call `setState`. In this case you could use `runOnce` to run something once during this widget's lifetime no matter the times `build` was called.

Worth a mention; there also is the `AsyncMemoizer.runOnce` for `async` functions from `package:async` but that one isn't aware of the call stack and works internally in a much simpler manner.

## Usage

Pure dart example;

```dart
import 'package:run_once/run_once.dart';

void main() async {
  /// This will print 'called 1' exactly 1 time although
  /// we call this function 10 times.
  for (var i = 0; i < 10; i++) {
    runOnce(() {
      print('called 1');
    });
  }

  /// This will print 'called 2' exactly 2 times as the [runOnce] simply
  /// isn't called in the same spot.
  runOnce(() {
    print('called 2');
  });
  runOnce(() {
    print('called 2');
  });

  /// This will print 'called 3' exactly 3 times although
  /// we call this function 15 times.
  /// Note the `forDuration` is exactly a [Duration] of 500 milliseconds.
  /// Using `forDuration` means for a duration of 500 milliseconds [runOnce]
  /// can only run once.
  /// So we loop 15 times in this loop and wait 100 milliseconds in each
  /// loop cycle; thus 'called 3' is printed exactly 3 times.
  for (var i = 0; i < 15; i++) {
    await Future.delayed(Duration(milliseconds: 100));

    runOnce(() {
      print('called 3');
    }, forDuration: Duration(milliseconds: 500));
  }
}
```

Flutter with a `StatefulWidget` example;

```dart
import 'package:run_once/run_once.dart';

// This example uses the state_notifier package
class _SomeWidgetState extends State<SomeWidget> {
  @override
  void dispose() {
    /// When this is called [runOnce] will be able to run once again
    /// for this class alone.
    runOnceDestroy();
    
    super.dispose();
  }
  
  @override
  Widget build(BuildContext context) {
    final state = context.watch<MyState>();
    
    return state.when(
      data: () => Placeholder(),
      loading: () {
        runOnce(() {
          /// This is always only called once 
          /// until [dispose] is called.
          Navigator.pushNamed(context, '/b');
        });

        return Placeholder();
      },
    );
  }  
}
```

## Disclaimer

This library isn't really tested very comprehensively at all. So it might not work in every use case.