Closed kalafut closed 5 months ago
I've been hitting this issue too -- I can trigger it in certain scenarios by performing a hot reload. Not sure if it's related to #209 and #206.
Hot reload should have been fixed, but have not run into with my tests. Would love to find a way to simulate hot reload in tests too.
Can you provide a minimal example to reproduce the issue?
I've reproduced my original issue, but, this was specific to the use of signals with lite_ref
overrides.
I have a minimal here for that, but looking at it, my issue may be different than the one mentioned here in #245.
At least as of yesterday, I could reliably make this happen in my app. Hopefully that is still the case today 😅 and I'll see if I can strip it down to a minimal example.
OK, I think I've crunched this down to the essentials. Run it, press +, press Back, and it should crash (might take a few tries, and a larger number of initial items seems to make it occur more quickly).
import 'package:flutter/material.dart';
import 'package:random_string/random_string.dart';
import 'package:signals/signals_flutter.dart';
final games = mapSignal(<String, String>{});
final filteredGames = computed(() {
final v = games.values.toList();
v.sort((a, b) =>
b.compareTo(a)); // If I remove this statement, the bug disappears ?!?
return v;
});
void initStore() {
// The quantity of items here seems to affect the bug. A lower number (say 5)
// and you have to press back a lot more times to trigger the bug.
for (var i = 0; i < 15; i++) {
games[randomAlpha(10)] = randomAlpha(10);
}
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(home: GameList());
}
}
class GameList extends StatelessWidget {
const GameList({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const GameEdit(),
),
);
},
child: const Icon(Icons.add),
),
body: Watch.builder(builder: (_) {
return ListView(
children: [
for (var game in filteredGames.value)
GameTile(
key: ValueKey(game), // if I don't set this, no crash
),
],
);
}));
}
}
class GameTile extends StatelessWidget {
const GameTile({
super.key,
});
@override
Widget build(BuildContext context) {
return Watch.builder(builder: (context) {
// If I make this const, the bug goes away ???!!??
return ListTile(
title: Text('yay'),
);
});
}
}
class GameEdit extends StatelessWidget {
const GameEdit({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Game Details'),
leading: BackButton(
onPressed: () {
games[randomAlpha(10)] = randomAlpha(10);
Navigator.pop(context);
},
),
),
body: const Text('Press back and it might crash'),
);
}
}
void main() {
WidgetsFlutterBinding.ensureInitialized();
initStore();
runApp(const MyApp());
}
Thanks for the code snippet, will try to reproduce 👍🏼
Yup -- the key seems to be when there is a Watch within a widget that already has a Watch further up the tree.
I'm using v5.0.0 and have a
ListView
withListItem
s that themselves useWatch.builder(...)
. When the whole list needs to rebuild (I'm speculating on that bit because this started failing when I added akey
attribute to fix an unrelated bug), I'm hitting this exception inframework.dart
:The caller, in
signals_flutter
, is inwatch/widget.dart
: