Riverpod: List provider is not rebuilding
Solution 1
Firstly, you are not creating the correct provider to listen to a StateNotifier
. You need to change this:
static final provider = StateProvider(
(ref) => CounterState(),
);
to this:
static final provider = StateNotifierProvider<CounterState, List<int>>(
(ref) => CounterState(),
);
Please refer to the Riverpod documentation about the different types of providers.
Secondly, you are not actually watching for state changes, but you are just getting the state object from the notifier.
Change this line:
var count = watch(CounterState.provider.notifier).state.length;
to this:
final count = watch(CounterState.provider).length;
also, your increment method is not correct for StateNotifier
providers. Please change this:
context.read(CounterState.provider.notifier).state.add(_count);
to this:
context.read(CounterState.provider.notifier).add(_count);
It should rebuild now when the state changes. However, you do need an implementation of your add
method that actually changes the state object itself. I would suggest the second variant you mentioned, that is in my opinion the nicest way to do this:
add(int p) {
state = [...state, p];
}
Solution 2
@TmKVU explained well, so I'm skipping that part. You can also follow riverpod document.
here is my example of riverPod:
Your widget
import 'dart:math';
import 'package:stack_overflow/exports.dart';
class CounterState extends StateNotifier<List<int>> {
static final provider = StateNotifierProvider(
(ref) => CounterState(),
);
int get last {
print('last');
return state.last;
}
int get length {
print('len');
return state.length;
}
// the body of this will be provided below
add(int p) {}
CounterState() : super(<int>[0]);
}
class MyHomePageSSSS extends ConsumerWidget {
@override
Widget build(BuildContext context, watch) {
void _incrementCounter() {
final _count = Random.secure().nextInt(100);
context.read(CounterState.provider.notifier).state =
context.read(CounterState.provider.notifier).state..add(_count);
}
final countprovider = watch(CounterState.provider);
return Scaffold(
appBar: AppBar(),
body: Center(
child: Text(
'You have pushed the button this many times: ${countprovider.length}',
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
child: Icon(Icons.add),
),
);
}
}
Adnan
Junior computer engineering student, Full-time Software engineer. mainly focused on flutter.
Updated on December 31, 2022Comments
-
Adnan over 1 year
Flutter riverpod is not notifying the
Consumer
on the state change when theStateNotifier
's type isList
, while the same implementation works just fine for other types.here, I provided a minimal reproducable example:
import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return ProviderScope( child: MaterialApp( home: MyHomePage(), ), ); } } class CounterState extends StateNotifier<List<int>> { static final provider = StateProvider( (ref) => CounterState(), ); int get last { print('last'); return state.last; } int get length { print('len'); return state.length; } // the body of this will be provided below add(int p) {} CounterState() : super(<int>[0]); } class MyHomePage extends ConsumerWidget { @override Widget build(BuildContext context, watch) { void _incrementCounter() { final _count = Random.secure().nextInt(100); context.read(CounterState.provider.notifier).state.add(_count); } var count = watch(CounterState.provider.notifier).state.length; return Scaffold( appBar: AppBar(), body: Center( child: Text( 'You have pushed the button this many times: $count', ), ), floatingActionButton: FloatingActionButton( onPressed: _incrementCounter, child: Icon(Icons.add), ), ); } }
as for the
add
method, I tried implementing it in a lot of ways, but neither works.here is what I tried:
1: just add it straight away:
add(int p) { state.add(p); }
2: I also tried the solution suggested in this answer:
add(int p) { state = [...state, p]; }
3: I tried to destroy the list entirely, and reassign it:
add(int p) { final _state = []; // copy [state] to [_state] for (var item in state) { _state.add(item); } // empty the state state = []; // add the new element _state.add(p); // refill [state] from [_state] for (var item in _state) { state.add(item); } print(state.length); // it continues until here and prints }