routemaster icon indicating copy to clipboard operation
routemaster copied to clipboard

Incorrect interaction with the bloc

Open oxid72 opened this issue 3 years ago • 2 comments

hi! I noticed that when using the routemaster, the state change event is triggered twice. With the same code, a regular router works as expected. I created a small project to test the behavior.

environment:
  sdk: ">=2.12.0 <3.0.0"
dependencies:
  flutter:
    sdk: flutter
  flutter_bloc: ^7.2.0
  routemaster: ^0.9.5
import 'package:flutter/scheduler.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:routemaster/routemaster.dart';

Future<void> main() async {
  runApp(TestApp());
}

const isNative = false;

class TestApp extends StatelessWidget {
  final routes = RouteMap(routes: {
    '/': (_) => MaterialPage(child: HomePage()),
    '/test': (_) => MaterialPage(child: TestPage()),
  });

  @override
  Widget build(BuildContext context) {
    return isNative
        ? MaterialApp(home: HomePage())
        : MaterialApp.router(
            routeInformationParser: const RoutemasterParser(),
            routerDelegate: RoutemasterDelegate(
              routesBuilder: (_) => routes,
            ),
          );
  }
}

// Pages

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('page 1'),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          if (isNative) {
            Route route = MaterialPageRoute(builder: (context) => TestPage());
            Navigator.push(context, route);
          } else {
            Routemaster.of(context).push('/test');
          }
        },
      ),
      body: const Text('page 1'),
    );
  }
}

class TestPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocProvider<TestCubit>(
      create: (_) => TestCubit(),
      child: BlocBuilder<TestCubit, TestState>(builder: (context, state) {
        print(state); // <= 'SecondState' printed twice!!!

        if (state is SecondState) {
          if (isNative) {
            SchedulerBinding.instance!.addPostFrameCallback((_) {
              Navigator.pop(context);
            });
          } else {
            Routemaster.of(context).pop();
          }
        }

        return Scaffold(
          appBar: AppBar(
            title: const Text('page 2'),
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: () {
              context.read<TestCubit>().call();
            },
          ),
          body: const Text('page 2'),
        );
      }),
    );
  }
}

// States
abstract class TestState {}

class InitState extends TestState {}

class SecondState extends TestState {}

//Cubit
class TestCubit extends Cubit<TestState> {
  TestCubit() : super(InitState());

  Future<void> call() async {
    emit(SecondState());
  }
}

oxid72 avatar Sep 29 '21 12:09 oxid72

Hello i think it's the bloc behavior, it think the BlocBuilder will rebuild if the state is different from the previous one You can add in your bloc build in order to prevent twice build : buildWhen(state1, state2) => state1 != state2, //or something similar

And in the cubit, you can try to emit a const

Future<void> call() async {
    emit(const SecondState());
  }

nbourdin avatar Oct 04 '21 07:10 nbourdin

Thanks for the answer, I'll try

oxid72 avatar Oct 04 '21 14:10 oxid72