How to make http.post call in riverpod?
You should use a state notifier provider since you already have a repository that handles your API calls. First you can create a state for the provider like below(I am using the Equatable Package):
abstract class FetchUserState extends Equatable {
FetchUserState();
}
class UserFetchInitial extends FetchUserState {
UserFetchInitial();
@override
List<Object> get props => [];
}
class UserFetched extends FetchUserState {
UserFetched();
@override
List<Object> get props => [];
}
class UserFetching extends FetchUserState {
UserFetching();
@override
List<Object> get props => [];
}
class UserFetchError extends FetchUserState {
UserFetchError();
@override
List<Object> get props => [];
}
Next, we create a StateNotifierProvider
final userProvider =
StateNotifierProvider<UserController>((ref) => UserController());
Next we create the User Controller that extends our state
class UserController extends StateNotifier<FetchUserState> {
UserController() :
super(UserFetchInitial());
void fetchUser(String mobile, String password) async {
final userRepository = UserRepository();
state = UserFetching();
try {
final res = await userRepository.fetchUser(mobile, password);
if (res) {
state = UserFetched();
} else {
state = UserFetchError();
}
} catch (e) {
state = UserFetchError();
}
}
}
Finally, in your onPressed on your UI, You can easily do:
context.read(userProvider).fetchUser(_phoneController.text.trim(),
_passwordController.text);
Let me know if this works for you.
Mr.PY
Updated on December 27, 2022Comments
-
Mr.PY over 1 year
I am trying to make a post-call that would send form data to API and get a response.
I would like to make a network post-call which sends the mobile, password, and get user data from user_repo and store it in the state to be accessed in the future.
I am unsure regarding how to add the user state provider and call it on button press.
for eg:
My AuthScreen: This is where the Ui is implemented.
class AuthScreen extends StatefulWidget { @override _AuthScreenState createState() => _AuthScreenState(); } class _AuthScreenState extends State<AuthScreen> { TextEditingController _phoneController; TextEditingController _passwordController; bool _isHidden = true; void _togglePasswordView() { setState(() { _isHidden = !_isHidden; }); } @override void initState() { super.initState(); _phoneController = TextEditingController(); _passwordController = TextEditingController(); } @override void dispose() { _phoneController.dispose(); _passwordController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return SafeArea( child: Scaffold( backgroundColor: Colors.white, resizeToAvoidBottomInset: false, body: Column( mainAxisAlignment: MainAxisAlignment.spaceAround, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Login', style: TextStyle( fontSize: 24.0, fontWeight: FontWeight.w500, ), ), TextField( keyboardType: TextInputType.phone, controller: _phoneController, decoration: InputDecoration( prefixIcon: Icon(Icons.phone_android), hintText: 'Enter your registered mobile number'), ), TextField( controller: _passwordController, decoration: InputDecoration( prefixIcon: Icon(Icons.lock), hintText: 'Enter your password', suffixIcon: InkWell( child: Icon( _isHidden ? Icons.visibility_off : Icons.visibility), onTap: _togglePasswordView, ), ), obscureText: _isHidden, ), RaisedButton( onPressed: ()=>{}, child: Text("login"), ), ], ), ), ); }
what should I write for onPressed? context.read(userState)??
User Modal:
class UserData { UserData({ this.id, this.name, this.mobile, this.email, this.image, }); String id; String name; String mobile; String email; String image; factory UserData.fromJson(Map<String, dynamic> json) => UserData( id: json["id"], name: json["name"], mobile: json["mobile"], email: json["email"], image: json["image"], ); Map<String, dynamic> toJson() => { "id": id, "name": name, "mobile": mobile, "email": email, "image": image, }; }
User Repo:
class UserRepository { Future<dynamic> fetchUser(String mobile, String password) async { var body = {"mobile": mobile, "password": password}; final response = await _implementation.post(my_url, body: body); return response; } }
State:
final userState = FutureProvider<dynamic>((ref) async { UserRepository().fetchUser(mobile, password); // How to make this work?? });
Edit: The solution provided by Tayormi worked perfectly.
I added a bit of code to store the user to access as necessary.
Created below state provider to store user:
final userData = StateProvider<UserData>((ref) => null);
Modified the userProvider to:
final userProvider = StateNotifierProvider<UserController>((ref) { final user = ref.read(userData); return UserController(user); });
within the try block of userController we can update the userData as below:
class UserController extends StateNotifier<FetchUserState> { final userData; UserController(this.userData) : super(UserFetchInitial()); void fetchUser(String mobile, String password) async { final userRepo = UserRepository(); state = UserFetching(); try { final response = await userRepo.fetchUser(mobile, password); if (response.id != null) { userData.state = response; state = UserFetched(); } else { state = UserFetchError(); } } catch (error) { print(error); state = UserFetchError(); } } }
All thanks to @Tayormi for helping me arrive at the solution..
-
Andrey Rankov about 3 yearsThank you for providing this! Can you put more details on how you did observe state changes - show loading animation till the user is fetched, show an error if user not found etc
-
-
Mr.PY over 3 yearsThank you for your answer. It worked perfectly. I was able to listen to the current user status and update UI accordingly. for eg: show loading animation till the user is fetched. show an error if user not found etc., I added a bit of code to store user details in state as below:
final userData = StateProvider<UserData>((ref) => null);
-
LearnFlutter about 2 yearsI was struggling with a task that i need to do and people told me that it can be done with riverpod, stackoverflow.com/questions/70980002/…
-
LearnFlutter about 2 yearsi simply need to have editedFirstName = TextEditingController(text: data3.firstName) globaly the declaration and assigning