beamer
beamer copied to clipboard
beamToNamed not rebuild widgets
I called context.beamToNamed("/books");
in HomeScreen, then
context.beamToNamed("/books/${e.id}");
in BooksScreen, finnally
context.beamToNamed("/books");
in BookDetailScreen;
As the result, why the BooksScreen build
method hadn`t been called again!
example:
home_screen.dart
import 'package:beamer/beamer.dart';
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Home Page"),
),
body: Container(
alignment: Alignment.center,
child: Column(children: [
TextButton(
onPressed: () => context.beamToNamed("/books"),
child: Text("Books"),
)
]),
),
);
}
}
books_screen.dart
import 'package:beamer/beamer.dart';
import 'package:beamer_demo/model/info.dart';
import 'package:flutter/material.dart';
class BooksScreen extends StatefulWidget {
const BooksScreen({Key? key}) : super(key: key);
@override
State<BooksScreen> createState() => _BooksScreenState();
}
class _BooksScreenState extends State<BooksScreen> {
@override
Widget build(BuildContext context) {
var data = Beamer.of(context).currentBeamLocation.data;
print(data);
var dataList = [
BookInfo(id: "22", title: "dog"),
BookInfo(id: "33", title: "cat"),
BookInfo(id: "44", title: "pig"),
];
var books = dataList
.map((e) => ListTile(
title: Text(e.title),
onTap: () {
context.beamToNamed("/books/${e.id}");
},
))
.toList();
return Scaffold(
appBar: AppBar(
title: const Text("Books Screen"),
),
body: Container(
child: SingleChildScrollView(
child: Column(children: books),
)),
);
}
}
book_details_screen.dart
import 'package:flutter/material.dart';
import 'package:beamer/beamer.dart';
class BookDetailsScreen extends StatelessWidget {
const BookDetailsScreen(this.bookId, {Key? key}) : super(key: key);
final String bookId;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Book Details Screen"),
),
body: Container(
child: Column(
children: [
Text("book $bookId"),
TextButton(
onPressed: () {
// context.beamBack(data: "2233");
context.beamToNamed("/books", data: "5566",);
},
child: Text("Back")),
],
),
),
);
}
}
main.dart
import 'package:beamer/beamer.dart';
import 'package:flutter/material.dart';
import 'book_details_screen.dart';
import 'books_screen.dart';
import 'home_screen.dart';
void main() {
runApp(BookApp());
}
class BookApp extends StatelessWidget {
BookApp({Key? key}) : super(key: key);
final routerDelegate = BeamerDelegate(
locationBuilder: RoutesLocationBuilder(
routes: {
// Return either Widgets or BeamPages if more customization is needed
'/': (context, state, data) => HomeScreen(),
'/books': (context, state, data) {
return BeamPage(
key: ValueKey('books'),
title: 'Books',
child: BooksScreen(),
onPopPage: (context,delegate, state, page) {
print("books");
return true;
}
);
},
'/books/:bookId': (context, state, data) {
// Take the path parameter of interest from BeamState
final bookId = state.pathParameters['bookId']!;
// Collect arbitrary data that persists throughout navigation
return BeamPage(
key: ValueKey('book-$bookId'),
title: 'A Book #$bookId',
// popToNamed: '/',
// type: BeamPageType.scaleTransition,
child: BookDetailsScreen(bookId),
);
}
},
),
);
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routeInformationParser: BeamerParser(),
routerDelegate: routerDelegate,
// backButtonDispatcher: BeamerBackButtonDispatcher(
// delegate: routerDelegate,
// ),
);
}
}
Hi @lemos1235 :wave: Sorry for a late response, I somehow missed that notification.
This is in fact an expected behavior. When you beam from /books/:id
to /books
, you are essentially doing a pop
and the BooksPage
is already built underneath so it stays as it were IF its key
is the same as it were during the last build. This is described a bit here: https://pub.dev/packages/beamer#page-keys
That being said, there are a few approaches you can consider.
- Including
data
in constructing akey
for theBeamPage
that constinasBooksScreen
. So something likeValueKey('books-$data')
. This is a very good choice for your example because you really are sending a different data when beaming back to/books
. - You could try an approach I described a bit in this recent article. It doesn't deal with
pop
s per se, but gives a more general solution for synchronizing data throughout navigation. - Have some state management for
BooksScreen
and overrideonPopPage
on itsBeamPage
where you can trigger a rebuild ofBooksScreen
through said state management.
I would suggest you try the first approach for now and then maybe second later. Third is a bit tricky and can get very messy.
Let me know if this helped.