Im making a Flutter app that shows a list of items, and I would like to filter this list based on a String in a search bar. I have Riverpod to provide a String that will be used in the filter. Base on this String I would like to change the suffixIcon
when the String is not empty.
I only able to update only one or the other (text in search bar or the icon) together they don't work.
What is going on?
final searchProvider = StateProvider<String>((ref) => '');
class OverviewScreen extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final houseDataValue = ref.watch(listHousesProvider);
final searchController = TextEditingController();
return Column(
children: [
Padding(
padding: EdgeInsets.only(top: 0.75.h, bottom: 1.5.h, right: 4.2.w, left: 4.2.w),
child: Container(
decoration: BoxDecoration(
color: AppColors.darkGray,
borderRadius: BorderRadius.circular(8.0),
),
child: Padding(
padding: EdgeInsets.only(left: 4.w, top: 0.4.h),
child: TextField(
controller: searchController,
cursorColor: AppColors.medium,
style: AppTypography.input,
decoration: InputDecoration(
hintText: 'Search for a home',
hintStyle: AppTypography.hint,
suffixIcon: IconButton(
icon: ref.watch(searchProvider).isNotEmpty // ICON DOES NOT UPDATE
? Icon(Icons.ac_unit_outlined)
: Icon(Icons.access_alarm_outlined),
onPressed: () {},
),
border: InputBorder.none,
),
onChanged: (value) {
// OR THE TEXT INSIDE THE SEARCH BAR
ref.read(searchProvider.notifier).update((state) => state = value);
},
),
),
),
),
],
);
}
}
In fact, you need to make another provider that would only control the empty string. Try this:
final searchProvider = StateProvider<String>((_) => '');
final searchIsEmptyProvider = Provider<bool>(
(ref) => ref.watch(searchProvider).isEmpty
);
Now your ui looks like this:
class OverviewScreen extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
print('$OverviewScreen been builded');
return Column(
children: [
TextField(
decoration: InputDecoration(
hintText: 'Search for a home',
suffixIcon: Consumer(
builder: (context, ref, _) => IconButton(
icon: ref.watch(searchIsEmptyProvider)
? Icon(Icons.access_alarm_outlined)
: Icon(Icons.ac_unit_outlined),
onPressed: () {},
),
),
border: InputBorder.none,
),
onChanged: (value) {
ref.read(searchProvider.notifier).update((_) => value);
},
),
],
);
}
}
I specifically used Consumer
to show that only the icon will be rebuilt, and not the entire OverviewScreen
widget.
Also note that you should create ANY controllers, text, focus, scroll, etc., only inside initState
, and dispose of them inside dispose
. This will help prevent memory leaks.
Happy coding!