i'm trying to use stateNotifierProvider in riverpod to fetch data. so i have a controller class that gets data from the repo and stores it in one of my states, now i am able to fetch the data and print it in the controller but im am not able to render/print the data in my UI. bellow are my code snippets. thanks.
this is how the controller look like.
final userDataProvider =
StateNotifierProvider<HomeController, HomeState>((ref) => HomeController());
class HomeController extends StateNotifier<HomeState> {
HomeController() : super(UserInitalState());
AuthRepository authRepository = AuthRepository();
void getUserData() async {
print("getting user data");
state = UserLoadingState();
try {
final res = await authRepository.getUserData();
// print(res);
if (res is Success) {
print(res.response);
state = UserLoadedState(userDataModel: res.response as UserModel);
print(state);
} else {
print("error here");
state = UserErrorState();
}
} catch (e) {
print("$e catch errorr");
state = UserErrorState();
}
}
}
and here is my state
abstract class HomeState extends Equatable {
HomeState();
}
class UserInitalState extends HomeState {
UserInitalState();
@override
List<Object> get props => [];
}
class UserLoadingState extends HomeState {
UserLoadingState();
@override
List<Object> get props => [];
}
class UserLoadedState extends HomeState {
UserModel userDataModel = UserModel();
UserLoadedState({required this.userDataModel});
@override
List<Object> get props => [];
}
class UserErrorState extends HomeState {
UserErrorState();
@override
List<Object> get props => [];
}
here is my UI
class HomeScreen extends ConsumerWidget {
HomeScreen({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
final user = ref.watch(userDataProvider);
print(user);
return Scaffold(
body: Center(
child: Text("HomeScreen"),
),
);
}
}
CodePudding user response:
The problem is that we need to make sure that the new state is a new object. The state also must not be a mutable object.
You may be try to features like "union types"/"sealed classes"/pattern matching. Using the freezed library, it's easy to do this:
@freezed
class HomeState with _$HomeState {
const factory ListState.userInitalState() = UserInitalState;
const factory ListState.userLoadingState() = UserLoadingState;
const factory ListState.userLoadedState(UserModel userDataModel) = UserLoadedState;
const factory ListState.userErrorState(String message) = UserErrorState; // usually, used message as parameter
}
and inside build method it looks like this:
final HomeState state = ref.watch(userDataProvider);
print(
state.when(
userInitalState: () => 'init',
userLoadingState: () => 'loading',
userLoadedState: (UserModel userDataModel) => 'loaded $userDataModel',
userErrorState: (String message) => 'error $message',
),
);
If there is no desire to pull an additional package in your project, you will have to keep an eye on the immutability of the objects.