【问题标题】:How to fetch network data on provider context change in Flutter如何在 Flutter 中获取有关提供者上下文更改的网络数据
【发布时间】:2021-05-31 20:57:48
【问题描述】:

我有一个带有一些奇怪功能的 Flutter 应用程序,但它是必需的。该应用程序的 BottomNavigationBar 页面包含在 IndexedStack 中,因此如果您转到此 IndexedStack 的其他页面,页面不会重新加载并保持持久性。

class _MyHomePageState extends State<MyHomePage> {
//...

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: IndexedStack(
        index: selectedIndex,
        children: bottomBarPages(),
      ),
      bottomNavigationBar: BottomNavigationBar(
        items: navItems,
        currentIndex: selectedIndex,
        onTap: _onNavItemTapped,
      ),
    );
  }
}

其中一个页面是 ProfilePage,您可以在其中选择用户列表。我使用如下所示的 ChangeNotifier:


class MainUserInfo extends ChangeNotifier {
  List<UserInfo> _users;
  UserInfo _chosenUser;
  //... some get/set/etc methods here
}

另一个底部导航栏页面 TheOtherPage 取决于所选用户 (_chosenUser),在 initState 上它从网络加载数据:

class TheOtherPage extends StatefulWidget {
//...

  bool isLoading = true;

  @override
  void initState() {
    super.initState();
    getAccountData();
  }

  void getAccountData() async {
    //some fetch happening here
    
    setState(() {
      model = response.data;
      isLoading = false;
    });
  }
}

问题是字段 _chosenUser 更改后,我需要 TheOtherPage 从网络加载所选用户的数据。但我不知道如何处理它。如果我使用 context.read 或 context.select 它肯定会跟踪更改的 _chosenUser,但不会获取新选择的数据:

var mainUserInfo = context.read<MainUserInfo>();
//or
var chosenUser = context.select<MainUserInfo, UserInfo>((userInfo) => userInfo.chosenUser);

而且我不想将 TheOtherPage 所需的数据保存在 UserInfo 对象中,因为数据太多,并且在 MainUserInfo._users 中为每个用户加载如此多的数据不是一个选项。 我还可以跟踪加载状态,因为使用“bool Isloading”我可以在获取所需数据时显示一些精美的占位符。

所以一般问题是如何使 TheOtherPage 获取有关 ProfilePage 上 ChangeNotifier 更改字段的数据。也许我的整个方法很糟糕,我不需要在这里使用 Provider 和 ChangeNotifier,我想看看任何建议。谢谢

【问题讨论】:

    标签: flutter flutter-provider flutter-state


    【解决方案1】:

    这是 provider 试图解决的一个典型案例:在 2 个小部件之间共享数据

    这是你的树结构:

    Scaffold
     \ IndexedStack
        \ ProfilePage  <- share MainUserInfo 
        \ TheOtherPage  <- share MainUserInfo 
    

    问题是您希望 TheOtherPage 收听 MainUserInfo 而它没有。 (因为 statefulwidget 中的initState() 只会被调用一次,即使状态改变了)

    我建议你可以听build方法里面的provider,用FutureBuilder处理加载状态:

    class _TheOtherPageState extends State<TheOtherPage> {
    //...
    
      @override
      void initState() {
        super.initState();
        // do nothing here
      }
    
      @override
      Widget build(BuildContext context) {      
        // rebuild everytime the MainUserInfo get notified by watching it
        // final mainUserInfo = context.watch<MainUserInfo>();
    
        // rebuild everytime the chosenUser change inside MainUserInfo
        final chosenUser = context.select<MainUserInfo, UserInfo>((userInfo) => userInfo.chosenUser);
    
        return FutureBuilder(
          future: getAccountData(chosenUser).
          builder: (BuildContext context, AsyncSnapshot snapshot) {
            if(snapshot.connectionState == ConnectionState.done && snapshot.hasData){
              model = snapshot.data;
    
              // return a page with the model
            } else {
    
              // return the loading placeholders 
            }
          }
        );
      }
    
      Future getAccountData(user) async {
        //some fetch happening here with the user
        // ...
    
        return response.data;
      }
    }
    

    您还可以尝试一件事:使用 const 关键字 (How to deal with unwanted widget build?)

      ...
      body: IndexedStack(
        index: selectedIndex,
        children: [
          ProfilePage(),
          const TheOtherPage(),    // here
        ],
      ),
      ...
    
    class TheOtherPage extends StatefulWidget {
      const TheOtherPage({Key key}) : super(key: key);   // and here
    
      @override
      _TheOtherPageState createState() => _TheOtherPageState();
    }
    

    【讨论】:

    • 感谢您的回答。这种方法存在一个问题,即 TheOtherPage 不再是持久的 IndexedStack:每次我点击相应的 BottomBar 按钮时,TheOtherPage 都会再次获取数据
    • 您的 BottomBar 按钮是否更改了 MainUserInfo 内的任何值?如果您只想监听MainUserInfo 内部的特定值变化,可以改用context.select
    • TheOtherPage 是否只显示chosenUser 的信息?我更新了答案。
    • 我已经将context.select 用于chosenUser。问题不在于提供者方法,我相信FutureBuilder 会以某种方式破坏IndexedStack。我只需按下BottomNavigationBarTheOtherPage 的按钮即可重建并获取数据
    • 谢谢!这可以节省一天的时间。我以前没用过const,所以其实我很糟糕,现在应该更频繁地使用const
    猜你喜欢
    • 1970-01-01
    • 2020-03-02
    • 1970-01-01
    • 2021-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-16
    • 1970-01-01
    相关资源
    最近更新 更多