如何避免每次导航到页面时都重新加载数据 [英] How to avoid reloading data every time navigating to page

查看:72
本文介绍了如何避免每次导航到页面时都重新加载数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正试图避免在扑朔迷离中重建 FutureBuilder .我已经尝试过在下面的Q中建议的解决方案.

I'm trying to avoid rebuilding FutureBuilder in flutter. I have tried solution suggested in below Q's.

如何仅在Flutter中解析JSON

将Flutter切换到Tab重新加载小部件并运行FutureBuilder

每次我导航至该页面时,我的应用仍会触发API.请指出我要去哪里了.

still my app fires API every time I navigate to that page. Please point me where I'm going wrong.

实用程序飞镖

//function which call API endpoint and returns Future in list
class EmpNetworkUtils {
    ...
    Future<List<Employees>> getEmployees(data) async {
        List<Employees> emps = [];
        final response = await http.get(host + '/emp', headers: { ... });
        final responseJson = json.decode(response.body);
        for (var empdata in responseJson) {
            Employees emp = Employees( ... );
            emps.add(emp);
        }
        return emps;
    }
}

EmpDetails.dart

class _EmpPageState extends State<EmpPage>{
    ...
    Future<List<Employees>>_getAllEmp;
    @override
    initState() {
        _getAllEmp = _getAll();
        super.initState();
    }
    Future <List<Employees>>_getAll() async {
        _sharedPreferences = await _prefs;
        String authToken = AuthSessionUtils.getToken(_sharedPreferences);
        return await EmpNetworkUtils().getEmployees(authToken);
    }

    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: new AppBar( ... ),
            body: Container(
                child: FutureBuilder(
                    future: _getAllEmp,
                    builder: (BuildContext context, AsyncSnapshot snapshot) { ... }
        )))
    }
}

更新:我在应用程序中使用了 bottomNavigationBar ,从该页面加载了此页面.

Update: I'm using bottomNavigationBar in my app, from which this page is loaded.

推荐答案

您正在 initState 中调用您的 getEmployees 函数,该函数每次在您的小部件上都将被调用被插入树中.如果要在第一次调用函数后保存数据,则必须有一个持久化的小部件.

You are calling your getEmployees function in initState, which is meant to be called every time your widget is inserted into the tree. If you want to save the data after calling your function the first time, you will have to have a widget that persists.

一个简单的实现方法是使用 InheritedWidget 和一个数据类:

An easy implementation would be using an InheritedWidget and a data class:

class InheritedEmployees extends InheritedWidget {
  final EmployeeData employeeData;

  InheritedEmployees({
    Key key,
    @required Widget child,
  })  : assert(child != null),
        employeeData = EmployeeData(),
        super(key: key, child: child);

  static EmployeeData of(BuildContext context) => (context.inheritFromWidgetOfExactType(InheritedEmployees) as InheritedEmployees).employeeData;

  @override
  bool updateShouldNotify(InheritedEmployees old) => false;
}

class EmployeeData {
  List<Employees> _employees;

  Future<List<Employees>> get employees async {
    if (_employees != null) return _employees;
    _sharedPreferences = await _prefs;
    String authToken = AuthSessionUtils.getToken(_sharedPreferences);
    return _employees = await EmpNetworkUtils().getEmployees(authToken);
  }
}

现在,您只需要将 InheritedEmployees 放置在不会被处置的地方,例如关于您的主页,或者如果您需要的话,甚至关于您的 MaterialApp ( runApp(InheritedEmployees(child:MaterialApp(..)); ).您还可以查看 AsyncMemoizer 如果更适合您,但是我提供的示例应该可以正常工作.

Now, you would only have to place your InheritedEmployees somewhere that will not be disposed, e.g. about your home page, or if you want, even about your MaterialApp (runApp(InheritedEmployees(child: MaterialApp(..));). This way the data is only fetched once and cached after that. You could also look into AsyncMemoizer if that suits you better, but the example I provided should work fine.

现在,您将要在 didChangeDependencies 中调用此 employees getter,因为您的 _EmpPageState 依赖于 InheritedEmployees 并且您需要查找它,这在 initState 中不会发生:

Now, you will want to call this employees getter in didChangeDependencies because your _EmpPageState is dependent on InheritedEmployees and you need to look that up, which cannot happen in initState:

class _EmpPageState extends State<EmpPage>{
    Future<List<Employees>>_getAllEmp;

    @override
    void didChangeDependencies() {
      _getAllEmp = InheritedEmployees.of(context).employees;
      super.didChangeDependencies();
    }

    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: new AppBar( ... ),
            body: Container(
                child: FutureBuilder(
                    future: _getAllEmp,
                    builder: (BuildContext context, AsyncSnapshot snapshot) { ... }
        )))
    }
}

我提到您的 State 现在依赖于您的 InheritedWidget ,但这并不重要,因为 updateShouldNotify 始终返回 false(不会再有任何其他版本).

I mentioned that your State is now dependent on your InheritedWidget, but that does not really matter as updateShouldNotify always returns false (there are not going to be any additional builds).

这篇关于如何避免每次导航到页面时都重新加载数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆