rodydavis / signals.dart

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

Two effect are being created when binding futureSignal using bindSignal from SignalMixin #316

Open SPiercer opened 1 week ago

SPiercer commented 1 week ago

in the code example below

example ```dart import 'package:flutter/material.dart'; import 'package:signals_flutter/signals_flutter.dart'; void main() { SignalsObserver.instance = LoggingSignalsObserver(); runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), useMaterial3: true, ), home: const MyHomePage(title: 'Flutter Demo Home Page'), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({super.key, required this.title}); final String title; @override State createState() => _MyHomePageState(); } class _MyHomePageState extends State { void _incrementCounter() { Navigator.push( context, MaterialPageRoute( builder: (_) => const SecondPage(), ), ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: Theme.of(context).colorScheme.inversePrimary, title: Text(widget.title), ), body: const Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 'Press the floating button to go to second screen', ), ], ), ), floatingActionButton: FloatingActionButton( onPressed: _incrementCounter, child: const Icon(Icons.navigate_next), ), ); } } class SecondPage extends StatefulWidget { const SecondPage({super.key}); @override State createState() => _SecondPageState(); } class _SecondPageState extends State with SignalsMixin { late final FutureSignal s; @override void initState() { super.initState(); s = this.bindSignal( futureSignal( () => Future.delayed(Durations.extralong4 * 2, () => 4), debugLabel: 'Second Page Future Signal', autoDispose: true, ), ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Second Page'), ), body: s.value.maybeMap( data: (data) => Center(child: Text('value is: $data')), loading: () => const Center(child: CircularProgressIndicator()), orElse: () => const Center(child: Text('Something else happened')), ), ); } } ```

i've created a futureSignal and binded it manually since there's no helper function to do so directly from the mixin and i've noticed in the logs it creates two effects.

[log] signal created: [1|Second Page Future Signal] => Instance of 'AsyncLoading<int>'  /// initial state
[log] computed created: [2|null]   /// streamSignal computed function
[log] effect created: [3|null]   /// idk what's that ?? ******** 
[log] computed updated: [2|null] => Instance of '_ControllerStream<int>' /// the initial state of the computed 
[log] effect called: [3|null] /// unknown effect gets updated *********
[log] effect created: [4|null] /// I think this is the widget effect got created.
[log] effect called: [4|null] /// it gets updated afterwards for the initial state i presume.
[log] signal updated: [1|Second Page Future Signal] => Instance of 'AsyncData<int>' /// the signal gets updated with the value state.
[log] effect called: [4|null] /// the widget effect gets updated with the new value

and the above is my analysis for the logs as well.. the effect with id 3 is the unknown one

so is that an expected behavior or is there something not right ?

rodydavis commented 3 hours ago

Interesting! I can look into it. But also need to add the future/stream helpers to the mixin too