如何在 riverpod 中调用 http.post?

How to make http.post call in riverpod?

我正在尝试进行 post 调用,将表单数据发送到 API 并获得响应。

我想打一个网络post-call,发送手机号、密码,并从user_repo获取用户数据,并将其存储在将来访问的状态。

我不确定如何添加用户状态提供程序并在按下按钮时调用它。

例如:

我的 AuthScreen:这是实施 Ui 的地方。

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"),
              ),
          ],
        ),  
      ),
    );
  }

我应该为 onPressed 写什么? context.read(用户状态)??

用户模式:

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,
      };
}

用户回购:

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;
  }
}

州:

final userState = FutureProvider<dynamic>((ref) async {
      UserRepository().fetchUser(mobile, password);
// How to make this work??
});

编辑: Tayormi 提供的解决方案完美运行。

我添加了一些代码来存储用户在需要时访问。

在状态提供程序下创建以存储用户:

final userData = StateProvider<UserData>((ref) => null);

将 userProvider 修改为:

final userProvider = StateNotifierProvider<UserController>((ref) {
  final user = ref.read(userData);
  return UserController(user);
});

在 userController 的 try 块中,我们可以按如下方式更新 userData:

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();
    }
  }
}

感谢@Tayormi 帮助我找到解决方案..

您应该使用状态通知程序提供程序,因为您已经有一个存储库来处理您的 API 调用。 首先,您可以为提供者创建一个状态,如下所示(我使用的是 Equatable 包):

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 => [];
}

接下来,我们创建一个StateNotifierProvider

final userProvider =
    StateNotifierProvider<UserController>((ref) => UserController());

接下来我们创建扩展状态的用户控制器

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();
    }
  }
}

最后,在 UI 上的 onPressed 中, 您可以轻松做到:

context.read(userProvider).fetchUser(_phoneController.text.trim(), 
                                                    _passwordController.text);

让我知道这是否适合你。