How to migrate from a StateNotifier
with complex state to a new Notifier
/AsyncNotifier
#1953
-
Hello! Need some help with migration to new version. Currently I'm using Now I have a state for pagination: part 'pagination_controller_state.freezed.dart';
/// State class for pagination screens.
@freezed
class PaginationControllerState<T> with _$PaginationControllerState<T> {
/// Factory for generating PaginationControllerState.
const factory PaginationControllerState({
/// If true, data is loading.
@Default(false) final bool isLoading,
/// If true, error has occurred.
@Default(false) final bool isError,
/// Page of the list.
final int? page,
/// Error.
final Object? error,
/// List of items.
final List<T>? items,
/// Поиск по тексту.
final String? search,
/// Filter by status enum.
@Default(EvaluationStatus.all) final EvaluationStatus filter,
/// No more pages to load.
@Default(false) final bool isEnd,
}) = _PaginationControllerState<T>;
} And I have a pagination controller abstraction: import 'package:flutter/foundation.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
/// Controller abstraction for pagination screens.
abstract class PaginationController<T>
extends StateNotifier<PaginationControllerState<T>> {
/// Creates a PaginationController.
PaginationController() : super(PaginationControllerState<T>()) {
fetchList();
}
/// Fetch list and manage states.
Future<void> fetchList({
final bool isRefresh = false,
final bool isSocketUpdate = false,
final String? search,
final EvaluationStatus? filter,
}) async {
if (isSocketUpdate || isRefresh || !state.isEnd) {
if (!state.isLoading) {
state = state.copyWith(
isLoading: !isSocketUpdate,
isError: false,
error: null,
page: isRefresh ? null : state.page,
items: isRefresh ? null : state.items,
search: search ?? state.search,
filter: filter ?? state.filter,
);
debugPrint('isSocketUpdate $isSocketUpdate');
final int nextPage = (state.page ?? 0) + 1;
try {
final List<T>? list = await getList(
isSocketUpdate ? 1 : nextPage,
length: isSocketUpdate ? (state.page ?? 1) * 20 : null,
isRefresh: isRefresh,
search: state.search ?? '',
filter: state.filter,
);
if (list != null) {
state = state.copyWith(
isEnd: list.length < 20,
isLoading: false,
items: <T>[
if (!isSocketUpdate) ...state.items ?? <T>[],
...list,
],
page: isSocketUpdate ? state.page : nextPage,
search: search ?? state.search,
filter: filter ?? state.filter,
);
}
} catch (e) {
debugPrint('ERROR in pagination controller: $e');
state = state.copyWith(
isLoading: false,
isError: true,
error: e.toErrorString(),
);
}
}
}
}
/// Load list from repository.
Future<List<T>?> getList(
final int page, {
required final EvaluationStatus filter,
final int? length,
final bool isRefresh = false,
final String? search,
});
} The abstraction has a preset method for operating with pagination and changing states. So it's only needed to override the method of getting the list and fix a type of list items. And I use these abstraction for several controllers, which handle states for different screens with paginated lists. Here is an example: /// Provider of [ParticipantsController].
final AutoDisposeStateNotifierProviderFamily<ParticipantsController,
PaginationControllerState<AccessModel>, int>
participantsControllerProvider = StateNotifierProvider.family.autoDispose<
ParticipantsController, PaginationControllerState<AccessModel>, int>((
final AutoDisposeStateNotifierProviderRef<ParticipantsController,
PaginationControllerState<AccessModel>>
ref,
final int id,
) {
return ParticipantsController(ref, id: id);
});
/// The controller of [EventScreen] states.
class ParticipantsController extends PaginationController<AccessModel> {
/// Creates [ParticipantsController].
ParticipantsController(this._ref, {required this.id});
/// Provider Ref.
final Ref _ref;
/// Event id.
final int id;
@override
Future<List<AccessModel>?> getList(
final int page, {
required final EvaluationStatus filter,
final int? length,
final bool isRefresh = false,
final String? search,
}) {
debugPrint('event controller id: $id');
return _ref.read(participantsRepositoryProvider(id)).fetchList(
page,
isRefresh: isRefresh,
search: search,
filter: filter,
length: length,
);
}
} I guess it is not possible to migrate this code to |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 5 replies
-
Hello! It's kind of broad. Do you have a more specific question? |
Beta Was this translation helpful? Give feedback.
Hello!
It's kind of broad. Do you have a more specific question?
All StateNotifier usages should be possible to migrate to Notifier/AsyncNotifier.