首页 > 解决方案 > 如何在 Riverpod 中进行 http.post 调用?

问题描述

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

我想做一个网络后调用,它发送手机、密码,并从 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(userState)??

用户模式:

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 帮助我找到解决方案..

标签: flutterauthenticationhttp-postriverpod

解决方案


您应该使用状态通知器提供程序,因为您已经有一个处理 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);

让我知道这是否适合您。


推荐阅读