【问题标题】:How to get CONTEXT for the provider to work? Flutter如何让提供者工作的上下文?扑
【发布时间】:2020-04-10 16:57:43
【问题描述】:

在未来的 fetchStudentInfo() 函数中,我想使用 Auth 类中的 userId 进行过滤。 userId 嵌入在 URL 中,它将从数据库中检索数据。但是,问题在于函数本身缺少上下文。但是,我想不出一种在上下文中传递的方法。如果有任何传说可以帮助我,那就太好了。从互联网检索数据的解决方案可以在颤振文档中找到。而且我不想硬编码 userId。

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:provider/provider.dart';
import '../model/student.dart';
import '../provider/auth.dart';

Future<Student> fetchStudentInfo() async {
  final auth = Provider.of<Auth>(context);
  final response = await http.post(
      'https://intermediary-sharpe.000webhostapp.com/Student/read_one.php?userId=$auth.userId');

  if (response.statusCode == 200) {
    return Student.fromJson(json.decode(response.body));
  } else {
    throw Exception('Failed');
  }
}

class ProfileScreen extends StatefulWidget {
  @override
  _ProfileScreenState createState() => _ProfileScreenState();
}

class _ProfileScreenState extends State<ProfileScreen> {
  Future<Student> student;
  @override
  void initState() {
    // TODO: implement initState

    super.initState();
    student = fetchStudentInfo();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: FutureBuilder<Student>(
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            return Text(snapshot.data.studentId);
          } else if (snapshot.hasError) {
            return Text('${snapshot.error}');
          }
          return CircularProgressIndicator();
        },
        future: student,
      ),
    );
  }
}
import 'package:flutter/cupertino.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'dart:async';
import 'package:shared_preferences/shared_preferences.dart';
import '../model/http_exception.dart';

class Auth with ChangeNotifier {
  String _token;
  DateTime _expiryDate;
  String userId;
  Timer _authTimer;

  bool get isAuthenticated {
    return token != null;
  }

  String get token {
    if (_expiryDate != null &&
        _expiryDate.isAfter(DateTime.now()) &&
        _token != null) {
      return _token;
    }
    return null;
  }

  Future<void> _authenticate(
      String email, String password, String urlSegment) async {
    final url =
        'https://identitytoolkit.googleapis.com/v1/accounts:$urlSegment?key=AIzaSyCkNZysDY4PGpScw2jUlBpd0mvpGjgSEag';
    try {
      final response = await http.post(
        url,
        body: json.encode(
          {
            'email': email,
            'password': password,
            'returnSecureToken': true,
          },
        ),
      );
      final responseData = json.decode(response.body);
      if (responseData['error'] != null) {
        throw HttpException(responseData['error']['message']);
      }
      _token = responseData['idToken'];
      userId = responseData['localId'];
      _expiryDate = DateTime.now().add(
        Duration(
          seconds: int.parse(
            responseData['expiresIn'],
          ),
        ),
      );
      _autoLogout();
      notifyListeners();
      final prefs = await SharedPreferences.getInstance();
      final userData = json.encode({
        'token': _token,
        'userId': userId,
        'expiryDate': _expiryDate.toIso8601String(),
      });
      prefs.setString('userData', userData);
    } catch (error) {
      throw error;
    }
  }

  //Auto Login Function
  Future<bool> tryAutoLogin() async {
    final prefs = await SharedPreferences.getInstance();
    if (!prefs.containsKey('userData')) {
      return false;
    }
    final extractedUserData =
        json.decode(prefs.getString('userData')) as Map<String, Object>;
    final expiryDate = DateTime.parse(extractedUserData['expiryDate']);
    if (expiryDate.isBefore(DateTime.now())) {
      return false;
    }
    _token = extractedUserData['token'];
    userId = extractedUserData['userId'];
    _expiryDate = expiryDate;
    notifyListeners();
    _autoLogout();
    return true;
  }

  //SignUp function
  Future<void> signUp(String email, String password) async {
    return _authenticate(email, password, 'signUp');
  }

  //Login Function
  Future<void> login(String email, String password) async {
    return _authenticate(email, password, 'signInWithPassword');
  }

  //Logout Function
  Future<void> logout() async {
    _token = null;
    userId = null;
    _expiryDate = null;
    if (_authTimer != null) {
      _authTimer.cancel();
      _authTimer = null;
    }
    notifyListeners();
    final prefs = await SharedPreferences.getInstance();
    prefs.clear();
  }

  //Auto Logout function
  void _autoLogout() {
    if (_authTimer != null) {
      _authTimer.cancel();
    }
    final timeToExpiry = _expiryDate.difference(DateTime.now()).inSeconds;
    _authTimer = Timer(Duration(seconds: timeToExpiry), logout);
  }

  //PHP related functions

}

提前谢谢你。

【问题讨论】:

    标签: flutter state provider


    【解决方案1】:

    将上下文传递给fetchStudentInfo不是最简单的解决方案吗?

    您可以将fetchStudentInfo() 更改为fetchStudentInfo(BuildContext context)。然后,当您调用该方法时,您将传入所需的上下文。这样,您就有了可用的适当上下文。

    【讨论】:

    • 在我将 fetchStudentInfo() 修改为 fetchStudentInfo(BuildContext context) 后,initState 中的函数出现错误。但是,如果我将上下文传递给参数,则会发生错误,编译器消息:lib/main.dart:1:8: Error: Not found: 'dart:js' import 'dart:js';
    • 看看你的进口。也许您从错误的包中导入 BuildContext
    【解决方案2】:

    我同意@lyio,你需要修改函数来传递上下文,但是在传递上下文之后,你不能像documentation of initState中所说的那样从initState调用它

    BuildContext.dependOnInheritedWidgetOfExactType 来自这个方法。但是didChangeDependencies会在这个方法之后立即被调用,BuildContext.dependOnInheritedWidgetOfExactType可以在那里使用。

    在后台使用 Provider.of(context) 获取提供程序正在使用继承的小部件,因此无法使用 initState 的上下文调用

    所以实现而不是 initState 使用 didChangeDependencies 来调用您的 fetchStudentsInfo(context) 方法

    【讨论】:

    • 天哪!这解决了我的问题!非常感谢。祝你有美好的一天。
    【解决方案3】:
    如果您没有在 state 类之外使用 `fetchStudentInfo()`,那么只需将该方法移动到 state 类中,问题就会得到解决。

    因为任何状态类都有一个默认定义的context getter。/

    我才意识到这个答案是多么的不恰当。

    更新: 根据@dlohani 的回答,应该使用didChangeDependencies 而不是initState

    所以你可以做的是:

    1. fetchStudentInfo 方法中将BuildContext 作为参数传递
    2. 在状态类中覆盖 didChangeDependencies 并从这里调用 fetchStudentInfo 而不是 initState

    【讨论】:

      猜你喜欢
      • 2020-04-07
      • 1970-01-01
      • 1970-01-01
      • 2019-07-10
      • 2023-03-21
      • 2022-11-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多