Skip to content

Instantly share code, notes, and snippets.

@marcoredz
Last active January 27, 2025 20:30
Show Gist options
  • Select an option

  • Save marcoredz/f88cdef264faaf8316e0c8a0487460c7 to your computer and use it in GitHub Desktop.

Select an option

Save marcoredz/f88cdef264faaf8316e0c8a0487460c7 to your computer and use it in GitHub Desktop.
Bloc list performance playground
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
Color getRandomColor() {
return Color((Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0);
}
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) => const MaterialApp(home: HomePage());
}
class ColorItem {
ColorItem({required this.index, required this.color, this.isLoading = false});
final int index;
final Color color;
final bool isLoading;
@override
bool operator ==(covariant ColorItem other) {
if (identical(this, other)) return true;
return other.index == index &&
other.color == color &&
other.isLoading == isLoading;
}
@override
int get hashCode => index.hashCode ^ color.hashCode ^ isLoading.hashCode;
ColorItem copyWith({
int? index,
Color? color,
bool? isLoading,
}) {
return ColorItem(
index: index ?? this.index,
color: color ?? this.color,
isLoading: isLoading ?? this.isLoading,
);
}
}
class ColorsState {
ColorsState({required int size, List<ColorItem>? colors})
: colors = colors ??
List.generate(size,
(index) => ColorItem(index: index, color: getRandomColor()));
final List<ColorItem> colors;
ColorsState copyWith({List<ColorItem>? colors}) {
return ColorsState(
size: colors?.length ?? this.colors.length, colors: colors);
}
@override
bool operator ==(Object other) => false;
@override
int get hashCode => colors.hashCode;
}
class ColorsCubit extends Cubit<ColorsState> {
ColorsCubit() : super(ColorsState(size: 20));
Future<void> toggle(int index) async {
// Set loading state
state.colors[index] = state.colors[index].copyWith(isLoading: true);
print('$index: ${state.colors[index].isLoading}');
emit(state);
await Future.delayed(const Duration(seconds: 1));
// Update color and unset loading state
state.colors[index] = state.colors[index].copyWith(
color: getRandomColor(),
isLoading: false,
);
print('$index: ${state.colors[index].isLoading}');
emit(state);
}
}
class IndexCubit extends Cubit<int> {
IndexCubit(int index) : super(index);
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) => ColorsCubit(),
child: Scaffold(body: const _GridView()),
);
}
}
class _GridView extends StatelessWidget {
const _GridView();
@override
Widget build(BuildContext context) {
print('### _GridView build ###');
return GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 20,
),
itemCount: context.select(
(ColorsCubit cubit) => cubit.state.colors.length,
),
itemBuilder: (_, index) {
return _GridItem(index);
},
);
}
}
class _GridItem extends StatelessWidget {
final int index;
const _GridItem(this.index);
@override
Widget build(BuildContext context) {
final colorItem = context.select(
(ColorsCubit cubit) => cubit.state.colors[index],
);
print('### GridItem build $index - ${colorItem.color} ###');
return GestureDetector(
onTap: () => context.read<ColorsCubit>().toggle(index),
child: colorItem.isLoading
? const Center(
child: SizedBox(
width: 24,
height: 24,
child: CircularProgressIndicator(strokeWidth: 2),
),
)
: ColoredBox(color: colorItem.color),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment