from te first page of Rivepod library I found this example.
final counterProvider = StateNotifierProvider<Counter, int>((ref) {
return Counter();
});
class Counter extends StateNotifier<int> {
Counter() : super(0);
void increment() => state++;
}
Now, what I want to ask is: what is the right way to do something like this below?
class Counter extends StateNotifier<int> {
Counter({int? value}) : super(value ?? 0);
void increment() => state++;
}
I want that my counterProvider can have optional parameters in input, my use case is a StateNotifier used to manage a edit/create page.
You can do like this:
final valueProvider = StateProvider<Counter, int>((ref) => return 5);
final counterProvider = StateNotifierProvider<Counter, int>((ref) {
final value = ref.watch(valueProvider);
return Counter(value);
});
class Counter extends StateNotifier<int> {
Counter(int value) : super(value ?? 0);
void increment() => state++;
}
Also, you can try using the modifier .family
That change state provider you can try like this:
ref.read(valueProvider.notifier).update((state) => 212);
// or use
...
ProviderScope(
overrides: [
valueProvider.overrideWithValue(21332432),
],
child: MyApp(),
),
...
You can see about it here.
to have an optional parameter, this is how to do it:
class Counter extends StateNotifier<int> {
Counter({int value = 0}) : super(value);
void increment() => state++;
}
Related
I want to use fetchdata() in another provider method and initialise variables.
you can use MultiProvider with ChangeNotifierProxyProvider
Action Class ( FirstModel )
class FirstModel with ChangeNotifier {
List<Strings> _names = ["Sat", "Sat2", "Sat3"];
List<Strings> get names {
return _names ;
}
}
Action Class ( SecondModel )
class SecondModel with ChangeNotifier {
SecondModel(this.firstModel);
final FirstModel firstModel;
List<Strings> getNames(){
return firstModel.names;
}
}
In main.dart just update the Multiprovider, example below
void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider<FirstModel>(create: (_) => FirstModel()),
ChangeNotifierProxyProvider0<SecondModel>(
create: (BuildContext context) =>
SecondModel(Provider.of<FirstModel>(context, listen: false)),
update: (BuildContext context, SecondModel secondModel) =>
SecondModel(Provider.of<FirstModel>(context, listen: false)),
),
],
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return const MaterialApp(
home: MyHomePage(),
);
}
}
Similar other class also avilable...
For More Information please refer below link...
ChangeNotifierProxyProvider0 class API
If someone still has difficulties with this then maybe this will help:
Accessing one provider method into another provider:-
class 1:-
class OneState extends ChangeNotifier {
List<Strings> _names = ["Alex", "Brad", "Carol"];
List<GlobalKey> get names=> _names;
updateNames(
{required List<Strings> names}) {
_names = names;
notifyListners();
}
}
class 2:-
class AnotherState extends ChangeNotifier {
AnotherState({required this.watchOneStateProviderValue}); //<- Notice this.
OneState watchOneStateProviderValue; //<- Notice this.
late List<int> _iq;
List<GlobalKey> get iq=> _iq;
createIQFromNames() {
// Getting names from another provider.
List<String> names = watchOneStateProviderValue.names; //<- Notice this.
_iq = [];
for(var name in names){
if(name == "Park Ju-hyun"){
iq.add(99999);
} else {
iq.add(0);
}
}
notifyListners();
}
}
Now declare providers like this:-
final oneStateProvider =
ChangeNotifierProvider((ref) => OneState());
final anotherStateProvider = ChangeNotifierProvider((ref) {
// We use `ref.watch` to watch another provider, and we pass it the provider
// that we want to consume. Here: oneStateProvider
final CalendarPropertiesState watchCalendarPropertiesStateProviderValue =
ref.watch(calendarPropertiesStateProvider);
// We can then use the result to do something based on the value of `oneStateProvider`.
return AnotherState(watchOneStateProviderValue: watchOneStateProviderValue);
});
var prevProvider = Provider.of<PrevProvider>(context, listen: false);
await prevProvider.fetchdata();
Hope it will work
I'm getting this error and I have no clue where it's coming from.
class Routes extends StatelessWidget {
#override
Widget build(BuildContext context) {
return BlocBuilder<RoutesBloc, RoutesEvent>( // <-- It occurs here
builder: (context, state) {
return Text('...');
},
);
}
}
Full error:
lib/screens/home_screen.dart:86:12: Error: Type argument 'RoutesBloc' doesn't conform to the bound 'BlocBase' of the type variable 'B' on 'BlocBuilder'.
'RoutesBloc' is from '/blocs/routes/routes_bloc.dart' ('lib/blocs/routes/routes_bloc.dart').
'BlocBase' is from 'package:bloc/src/bloc.dart' ('../../AppData/Local/Pub/Cache/hosted/pub.dartlang.org/bloc-7.0.0/lib/src/bloc.dart').
Try changing type arguments so that they conform to the bounds.
return BlocBuilder<RoutesBloc, RoutesEvent>(
^
I use a multiplocprovider in my main.dart like this:
MultiBlocProvider(
providers: [
...,
BlocProvider<RoutesBloc>(
create: (_) => RoutesBloc(
apiRepository: ApiRepository.create(),
)..add(RoutesLoaded()),
),
],
child: AppView(),
)
routes_state.dart:
abstract class RoutesState extends Equatable {
const RoutesState();
#override
List<Object> get props => [];
}
class RoutesLoadInProgress extends RoutesState {}
class RoutesLoadSuccess extends RoutesState {
final List<BoulderingRoute> routes;
const RoutesLoadSuccess([this.routes = const []]);
#override
List<Object> get props => [routes];
}
class RoutesLoadFailure extends RoutesState {}
routes_event.dart:
abstract class RoutesEvent extends Equatable {
const RoutesEvent();
#override
List<Object> get props => [];
}
class RoutesLoaded extends RoutesEvent {}
class RouteAdded extends RoutesEvent {
final BoulderingRoute route;
const RouteAdded({this.route}) : assert(route != null);
#override
List<Object> get props => [route];
}
class RouteUpdated extends RoutesEvent {
final BoulderingRoute route;
const RouteUpdated({this.route}) : assert(route != null);
#override
List<Object> get props => [route];
}
class RouteDeleted extends RoutesEvent {
final BoulderingRoute route;
const RouteDeleted({this.route}) : assert(route != null);
#override
List<Object> get props => [route];
}
routes_bloc.dart:
class RoutesBloc extends Bloc<RoutesEvent, RoutesState> {
final ApiRepository _apiRepository;
RoutesBloc({ApiRepository apiRepository})
: assert(apiRepository != null),
this._apiRepository = apiRepository,
super(RoutesLoadInProgress());
#override
Stream<RoutesState> mapEventToState(
RoutesEvent event,
) async* {
print(event);
if (event is RoutesLoaded) {
yield* _mapRoutesLoadedToState();
}
}
Stream<RoutesState> _mapRoutesLoadedToState() async* {
try {
print('start');
final List<BoulderingRoute> routes =
await _apiRepository.fetchBoulderingRoutes();
yield RoutesLoadSuccess(routes);
} catch (_) {
yield RoutesLoadFailure();
}
}
}
I firstly thought that there must be something wrong with my RoutesBloc but changing the blocbuilder to a bloc that I'm successfully using at another place ends up with the same error.
Does someone know where this is coming from?
It should be return BlocBuilder<RoutesBloc, RoutesState>
Check this: https://pub.dev/packages/flutter_bloc#blocbuilder
BlocBuilder<BlocA, BlocAState>(
builder: (context, state) {
// return widget here based on BlocA's state
}
)
I have this class:
class BeatCounter extends StateNotifier<int> {
BeatCounter() : super(8);
int get counter => state;
void increment() {
if (state < 16) {
state++;
print('State $state');
} else
return;
}
void decrement() {
if (state > 1) {
state--;
} else
return;
}
}
final beatCounterProvider = StateNotifierProvider((ref) => BeatCounter());
And want to access the state inside a class that extends a StatefullWidget that I don't want (/know how to) change. So I can't use 'with' to extend 'ConsumerWidget' or 'HookWidget'.
How do I get the state in this class?
class ChordsTrack extends BaseWidget {
ChordsTrack({Key key, #required this.sample}) : super(key: key);
final SOUND_SAMPLE sample;
#override
_ChordsTrackState createState() => _ChordsTrackState();
}
class _ChordsTrackState extends BaseState<ChordsTrack> {
MultitrackChordBassBoxCreator multitrackBox =
MultitrackChordBassBoxCreator();
List<bool> _data = List.generate(***BeatCounter().state***, (i) => false);
#override
void on<Signal>(Signal signal) {
setState(() => _data = AudioEngine.trackdata[widget.sample]);
}
...
}
Newbie question, I know, but would really appreciate some help.
I solved it this way.
class BeatCounter extends StateNotifier<int> {
BeatCounter() : super(8);
static int counter = 8; //*
void increment() {
if (state < 16) {
state++;
counter++; //*
} else
return;
}
void decrement() {
if (state > 1) {
state--;
counter--;//*
} else
return;
}
}
Is there a better option?
Just use context.read(beatCounterProvider) in your initState.
class _ChordsTrackState extends BaseState<ChordsTrack> {
MultitrackChordBassBoxCreator multitrackBox =
MultitrackChordBassBoxCreator();
List<bool> _data;
#override
void initState(){
super.initState();
_data = List.generate(context.read(beatCounterProvider).state, (i) => false);
}
#override
void on<Signal>(Signal signal) {
setState(() => _data = AudioEngine.trackdata[widget.sample]);
}
...
}
How to change the widgets in a list item in flutter using bloc pacakage.
Should i use BlockBuilder or listener on the whole ListView.builder or only the individual items.
It would be nice if u share an example or tutorial.
eg If i have a checkbox i need to change its state on clicking it.
These are my Bloc classes
Bloc
const String SERVER_FAILURE_MESSAGE = 'Server Failure';
const String CACHE_FAILURE_MESSAGE = 'Cache Failure';
class MarkAttendanceBloc extends Bloc<MarkAttendanceEvent, MarkAttendanceState> {
final MarkStudentPresent markStudentPresent;
final MarkStudentAbsent markStudentAbsent;
MarkAttendanceBloc({#required this.markStudentPresent,#required this.markStudentAbsent});
#override
MarkAttendanceState get initialState => MarkedInitial();
#override
Stream<MarkAttendanceState> mapEventToState(MarkAttendanceEvent event) async* {
yield MarkedLoading();
if(event is MarkAbsentEvent){
final remotelyReceived = await markStudentAbsent(MarkStudentParams(classId: event.classId, courseId: event.courseId,studentId: event.studentId));
yield* _eitherLoadedOrErrorState(remotelyReceived);
}
else if(event is MarkPresentEvent){
final remotelyReceived = await markStudentPresent(MarkStudentParams(classId: event.classId, courseId: event.courseId,studentId: event.studentId));
yield* _eitherLoadedOrErrorState(remotelyReceived);
}
}
Stream<MarkAttendanceState> _eitherLoadedOrErrorState(
Either<StudentDetailsFacultyFailure,int> failureOrClasses,
) async* {
yield failureOrClasses.fold(
(failure) => MarkedError(_mapFailureToMessage(failure)),
(studentId) => Marked(studentId),
);
}
String _mapFailureToMessage(StudentDetailsFacultyFailure failure) {
switch (failure.runtimeType) {
case ServerError:
return SERVER_FAILURE_MESSAGE;
default:
return 'No internet';
}
}
}
State
abstract class MarkAttendanceState extends Equatable{
const MarkAttendanceState();
}
class MarkedInitial extends MarkAttendanceState{
const MarkedInitial();
#override
List<Object> get props => [];
}
class MarkedLoading extends MarkAttendanceState{
const MarkedLoading();
#override
List<Object> get props => [];
}
class Marked extends MarkAttendanceState{
final int studentId;
Marked(this.studentId);
#override
List<Object> get props => [studentId];
}
class MarkedError extends MarkAttendanceState{
final String errorMessage;
MarkedError(this.errorMessage);
#override
List<Object> get props => [errorMessage];
}
Event
import 'package:equatable/equatable.dart';
abstract class MarkAttendanceEvent extends Equatable {
const MarkAttendanceEvent();
}
class MarkPresentEvent extends MarkAttendanceEvent {
final int studentId;
final int courseId;
final int classId;
MarkPresentEvent(this.studentId, this.courseId, this.classId);
#override
List<Object> get props =>[studentId,courseId,classId];
}
class MarkAbsentEvent extends MarkAttendanceEvent {
final int studentId;
final int courseId;
final int classId;
MarkAbsentEvent(this.studentId, this.courseId, this.classId);
#override
List<Object> get props =>[studentId,courseId,classId];
}
Maybe by now you have found a solution but this is how i managed to achieve the same functionality using flutter cubits.
This code is hand written and not tested but it should guide you to achieve your goal
1 Declare the class objects
class ClassItem{
int? price;
bool isChecked;
ClassItem({
this.price,
this.isChecked=false,
});
}
class ClassOverall{
List<ClassItem> items;
double? total;
ClassOverall(this.items,this.total);
}
Declare the cubit class
class OverallCubit extends Cubit<ClassOverall> {
OverallCubit(ClassOverallinitialState) : super(initialState);
void checkUncheckCart(int index) {
if (!state.items
.elementAt(index).isChecked) {
state.items
.elementAt(index).isChecked =
!state.items
.elementAt(index).isChecked;
var t_total = double.tryParse(state.items
.elementAt(index).price!)! * 1;
emit(OverallCubit (state.items,state.total));
} else {
state.items.elementAt(index).isChecked =
!state.items
.elementAt(index).isChecked;
emit(OverallCubit (state.items,state.total));
}
calculateTotal();
}
void calculateTotal() {
var tot = 0.0;
for (var tick in state.items) {
if (tick.isChecked) {
tot = (tick.t_total! + tot);
}
}
emit(OverallCubit (state.items,tot));
}
}
Declare the top class widget to hold the state
class TopState extends StatelessWidget {
#override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) => OverallCubit(ClassOverall(items,0)),//fetch items from your source
child: Home(),
);
}
}
Declare the stateful widget and add a bloc builder
class Home extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<Home> {
#override
Widget build(BuildContext context) {
return BlocBuilder<OverallCubit, ClassOverall>(
builder: (ctx, state) {
return Column(children:[
ListView.builder(
padding: EdgeInsets.all(0.0),
shrinkWrap: true,
itemCount: state.items.length,
itemBuilder: (context, index) {
return ListTile(
onTap: () {
ctx
.read<OverallCubit>()
.checkUncheckCart(index);
},
tileColor: state.elementAt(index).isChecked ? Colors.red : Colors.white
title: Text(state.items.elementAt(index).price!),
);
}),
Text(state.total.toString),
]);
});
}
}
I am using flutter_bloc in my application and referring to this sample. Now when I am running my application it gives me an error saying:
flutter: type 'MovieUninitialized' is not a subtype of type
'MovieLoaded' in type cast
My bloc contains three files: movie_state, movie_event, and movie_bloc
movie_state.dart
import 'package:equatable/equatable.dart';
import 'package:movie_project/models/movie.dart';
abstract class MovieState extends Equatable {
MovieState([List props = const []]) : super(props);
}
class MovieUninitialized extends MovieState {
#override
String toString() => 'MovieUninitialized';
}
class MovieError extends MovieState {
#override
String toString() => 'MovieError';
}
class MovieLoaded extends MovieState {
final List<Movie> movies;
final bool hasReachedMax;
// Keeps track of the page to fetch the latest movies from the api
final latestMoviesPage;
MovieLoaded({
this.movies,
this.hasReachedMax,
this.latestMoviesPage,
}) : super([movies, hasReachedMax, latestMoviesPage]);
MovieLoaded copyWith({
List<Movie> movies,
bool hasReachedMax,
int latestMoviesPage,
}) {
return MovieLoaded(
movies: movies ?? this.movies,
hasReachedMax: hasReachedMax ?? this.hasReachedMax,
latestMoviesPage: this.latestMoviesPage,
);
}
#override
String toString() =>
'PostLoaded { posts: ${movies.length}, hasReachedMax: $hasReachedMax }';
}
movie_event.dart
import 'package:equatable/equatable.dart';
abstract class MovieEvent extends Equatable {}
class Fetch extends MovieEvent {
#override
String toString() => 'Fetch';
}
movie_bloc.dart
class MovieBloc extends Bloc<MovieEvent, MovieState> {
final MovieRepository movieRepository;
MovieBloc({#required this.movieRepository});
#override
Stream<MovieState> transform(
Stream<MovieEvent> events,
Stream<MovieState> Function(MovieEvent event) next,
) {
return super.transform(
(events as Observable<MovieEvent>).debounceTime(
Duration(milliseconds: 500),
),
next,
);
}
#override
MovieState get initialState => MovieUninitialized();
#override
Stream<MovieState> mapEventToState(MovieEvent event) async* {
if (event is Fetch && !_hasReachedMax(currentState)) {
try {
if (currentState is MovieUninitialized) {
final movies = await movieRepository.fetchMovies(1);
yield MovieLoaded(
movies: movies,
hasReachedMax: false,
latestMoviesPage:
(currentState as MovieLoaded).latestMoviesPage + 1,
);
return;
}
if (currentState is MovieLoaded) {
final movies = await movieRepository
.fetchMovies((currentState as MovieLoaded).latestMoviesPage);
yield movies.isEmpty
? (currentState as MovieLoaded).copyWith(hasReachedMax: true)
: MovieLoaded(
movies: (currentState as MovieLoaded).movies + movies,
hasReachedMax: false,
latestMoviesPage:
(currentState as MovieLoaded).latestMoviesPage + 1,
);
}
} catch (_) {
print(_);
yield MovieError();
}
}
}
bool _hasReachedMax(MovieState state) =>
state is MovieLoaded && state.hasReachedMax;
}
I need to increment the latestMoviesPage until it reaches the max limit. If I remove latestMoviesPage from my bloc code issue gets resolves but I really need it to load more pages.
Instead of
latestMoviesPage: (currentState as MovieLoaded).latestMoviesPage + 1,
I need to write:
latestMoviesPage: 2,