Home > Enterprise >  riverpod stateNotifierProvider to fetch data
riverpod stateNotifierProvider to fetch data

Time:10-18

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.

  • Related