Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

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..


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
350 views
Welcome To Ask or Share your Answers For Others

1 Answer

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...