slovnicki / beamer

A routing package built on top of Router and Navigator's pages API, supporting arbitrary nested navigation, guards and more.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

BeamerDelegate fails with a runtime error in StreamBuilder<>...

yardwerkz opened this issue · comments

Describe the bug
A clear and concise description of what the bug is.

I have code which wraps a call to context.beamToNamed with a StreamBuilder<>:

import 'package:beamer/beamer.dart';
import 'package:flutter/material.dart';
import 'package:yardwerkz_flutter/blocs/bloc_provider.dart';
import 'package:yardwerkz_flutter/customer/blocs/address_suggestions_bloc.dart';
import 'package:yardwerkz_flutter/customer/blocs/yard_bloc.dart';
import 'package:yardwerkz_flutter/customer/models/yard.dart';
import 'package:yardwerkz_flutter/customer/screens/yard_screen.dart';

class AddressScreen extends StatelessWidget {
  const AddressScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Address')),
      body: const Padding(
        padding: EdgeInsets.all(16.0),
        child: MyAutocomplete(),
      ),
    );
  }
}

class MyAutocomplete extends StatefulWidget {
  const MyAutocomplete({Key? key}) : super(key: key);

  @override
  State<MyAutocomplete> createState() => _MyAutocompleteState();
}

class _MyAutocompleteState extends State<MyAutocomplete> {
  @override
  Widget build(BuildContext context) {
    final addressSuggestionsBloc =
        BlocProvider.of<AddressSuggestionsBloc>(context);
    final yardBloc = BlocProvider.of<YardBloc>(context);

    return StreamBuilder<List<String>>(
      stream: addressSuggestionsBloc!.suggestions,
      builder: (context, addressSnapshot) => StreamBuilder<Yard>(
          stream: yardBloc!.outYard,
          builder: (context, yardSnapshot) {
            if (!yardSnapshot.hasData) {
              return Autocomplete<String>(
                optionsBuilder: (textEditingValue) {
                  if (textEditingValue.text.isEmpty) {
                    return const <String>[];
                  } else {
                    addressSuggestionsBloc.input.add(textEditingValue.text);
                  }
                  if (addressSnapshot.hasData) {
                    return addressSnapshot.data!;
                  } else {
                    return const <String>[];
                  }
                },
                onSelected: (selected) {
                  yardBloc.inAddressString.add(selected);
                },
              );
            } else {
              final yard = yardSnapshot.data!;
              final lat = yard.location?.latitude ?? 0.0;
              final lng = yard.location?.longitude ?? 0.0;
              debugPrint('hasData: $lat, $lng');
              // FIXME: BeamerDelegate calls notifyListeners() which causes a bug.
              // context.beamToNamed('/customer/diagram?lat=$lat&lng=$lng');
              // FIXME: Use Navigator 1.0 to get around this
              Navigator.push(
                  context,
                  MaterialPageRoute(
                      builder: (context) => YardScreen(
                          initialLatitude: lat, initialLongitude: lng)));
              return const Center(
                child: CircularProgressIndicator(),
              );
            }
          }),
    );
  }
}

I am getting the following error:
The following assertion was thrown while dispatching notifications for BeamerDelegate:
setState() or markNeedsBuild() called during build.

This Router widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.
The widget on which setState() or markNeedsBuild() was called was: Router
dependencies: [UnmanagedRestorationScope]
state: _RouterState#644ac
The widget which was currently being built when the offending call was made was: StreamBuilder
dependencies: [_RouterScope]
state: _StreamBuilderBaseState<Yard, AsyncSnapshot>#13556
When the exception was thrown, this was the stack:
#0 Element.markNeedsBuild. (package:flutter/src/widgets/framework.dart:4651:9)
#1 Element.markNeedsBuild (package:flutter/src/widgets/framework.dart:4663:6)
#2 State.setState (package:flutter/src/widgets/framework.dart:1159:15)
#3 _RouterState._handleRouterDelegateNotification (package:flutter/src/widgets/router.dart:791:5)
#4 ChangeNotifier.notifyListeners (package:flutter/src/foundation/change_notifier.dart:403:24)
#5 BeamerDelegate.update (package:beamer/src/beamer_delegate.dart:452:7)

Beamer version: (e.g. v0.14.1, master, ...)
1.5.2
To Reproduce
Steps to reproduce the behavior:
See code above.
Expected behavior
A clear and concise description of what you expected to happen.
To navigate to the named page.
Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS: [e.g. iOS]
  • Browser [e.g. chrome, safari]
  • Version [e.g. 22]
    OS: Mac 13.3.1
    Browser: Chrome 112.0.5615.137
    Smartphone (please complete the following information):
  • Device: [e.g. iPhone6]
  • OS: [e.g. iOS8.1]
  • Browser [e.g. stock browser, safari]
  • Version [e.g. 22]

All iPhones and Androids

Additional context
Add any other context about the problem here.
The code referred to in the stack trace is a call to notifyListeners().