rodydavis / signals.dart

Reactive programming made simple for Dart and Flutter
http://dartsignals.dev
Apache License 2.0
438 stars 50 forks source link

Unhandled Exception: Null check operator used on a null value #199

Closed yousefak007 closed 7 months ago

yousefak007 commented 7 months ago

i made asyncWhen function like mobx


Future<void> asyncWhen(ComputedCallback<bool> compute,
    {Duration? timeout}) async {
  Computed<bool>? computedSignal = computed(compute);

  if (computedSignal.peek()) {
    computedSignal.dispose();
    return;
  }

  Completer<void>? completer = Completer();

  Timer? timer;
  EffectCleanup? disposer;

  void cleanUp() {
    disposer?.call();
    disposer = null;

    timer?.cancel();
    timer = null;

    computedSignal?.dispose();
    computedSignal = null;

    completer = null;
  }

  if (timeout != null) {
    timer = Timer(timeout, () {
      if (completer?.isCompleted == false) {
        completer?.completeError('WHEN_TIMEOUT');
      }
      cleanUp();
    });
  }

  disposer = computedSignal?.subscribe((value) {
    if (value) {
      if (completer?.isCompleted == false) {
        completer?.complete();
      }
      cleanUp();
    }
  });

  return completer!.future;
}

for test:


 final test = signal(false);

...

Future.delayed(
  const Duration(seconds: 4),
  () {
    test.value = true;
  },
);
await asyncWhen(() => test(), timeout: const Duration(seconds: 5));

and everything works fine, except there is an error showing in console:

[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Null check operator used on a null value
#0      _endBatch (package:signals_core/src/core/batch.dart:44:5)
#1      _Signal._updateValue (package:signals_core/src/core/signal.dart:354:7)
#2      _Signal._set (package:signals_core/src/core/signal.dart:334:7)
#3      _Signal.value= (package:signals_core/src/core/signal.dart:325:5)

after some investigation, the error came from devtool.dart file from _onEffectCalled callback

image

so using ! causing the null check exception, and also _effectCount[instance.globalId] ?? 0; what is doing without any assignation?

rodydavis commented 7 months ago

Got it, I just realized the onEffectCreated is not called for subscribe in signal/computed directly.

Thanks for capturing this!

rodydavis commented 7 months ago

One error with the code is if (computedSignal.peek()) will throw an error because the value has not been read.

A computed function will always throw an error if the value has not been created. I think the docs need to make that more clear

yousefak007 commented 7 months ago

One error with the code is if (computedSignal.peek()) will throw an error because the value has not been read.

A computed function will always throw an error if the value has not been created. I think the docs need to make that more clear

could you give me a case that could throw an exception?

yousefak007 commented 7 months ago

thanks after the upgrade, everything works fine, and there is no error, asyncWhen it's really very handy, it depends on the predicate with signals to make future

it can be nice if added to this library by default, what do you think?