【问题标题】:How to pass the data get from Home widget to it's child widgets in flutter?如何将从 Home 小部件获取的数据传递给它的子小部件?
【发布时间】:2021-02-07 04:21:36
【问题描述】:

我正在为一个社区开发一个应用程序,该应用程序具有登录、注册、会议和聊天功能。登录成功后,路由进入首页,底部有五个导航。我在此应用中使用 Firebase 进行身份验证和 Firestore。

我想在 Home 组件启动时获取一次数据并将数据传递给其他五个底部导航栏组件。 现在,每当我在导航组件之间切换时,我都会获取数据。这会增加 Firestore 的读取次数。

我尝试使用构造函数变量通过组件传递数据。但这不起作用。它显示数据无法传递到底部导航组件的错误这是我的代码。

Home.dart

class Home extends StatefulWidget {
  @override
  _HomeState createState() => _HomeState();
  User currentUser;
  String userId;
  Home({this.currentUser, this.userId});
}

class _HomeState extends State<Home> {
  CurrentUser userInfo;
  DocumentSnapshot doc;
  int _selectedIndex = 0;
  List<String> upcoming_seven_days;
  FirestoreService _firestoreService = FirestoreService();
  static const TextStyle optionStyle =
      TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
  static List<Widget> _widgetOptions = <Widget>[
    Dashboard(),
    MeetingList(),
    EventList(),
    Chat(),
    Profile(),
  ];

  static const List<Widget> _appBarText = <Widget>[
    Text(
      'Dashboard',
      style: TextStyle(
        fontWeight: FontWeight.w300,
        fontSize: 26,
      ),
    ),
    Text(
      'Meetings',
      style: TextStyle(
        fontWeight: FontWeight.w300,
        fontSize: 26,
      ),
    ),
    Text(
      'Events',
      style: TextStyle(fontWeight: FontWeight.w300, fontSize: 26),
    ),
    Text(
      'Chat',
      style: TextStyle(fontWeight: FontWeight.w300, fontSize: 26),
    ),
    Text(
      'Profile',
      style: TextStyle(fontWeight: FontWeight.w300, fontSize: 26),
    ),
  ];

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    //setCurrentUserID(widget.currentUser.uid);

    //setCurrentUserData(doc.data());
  }

  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: _appBarText.elementAt(_selectedIndex)),
      body: Container(
        padding: EdgeInsets.symmetric(horizontal: 10),
        width: double.maxFinite,
        child: _widgetOptions.elementAt(_selectedIndex),
      ),
      bottomNavigationBar: BottomNavigationBar(
        items: const <BottomNavigationBarItem>[
          BottomNavigationBarItem(
              icon: Icon(Icons.dashboard),
              title: Text('Dashboard'),
              backgroundColor: Colors.black),
          BottomNavigationBarItem(
              icon: Icon(Icons.people),
              title: Text('Meetings'),
              backgroundColor: Colors.black),
          BottomNavigationBarItem(
              icon: Icon(Icons.calendar_view_day),
              title: Text('Events'),
              backgroundColor: Colors.black),
          BottomNavigationBarItem(
              icon: Icon(Icons.chat),
              title: Text('Chat'),
              backgroundColor: Colors.black),
          BottomNavigationBarItem(
              icon: Icon(Icons.person),
              title: Text('Profile'),
              backgroundColor: Colors.black),
        ],
        currentIndex: _selectedIndex,
        selectedItemColor: Colors.lightBlue[200],
        onTap: _onItemTapped,
        elevation: 8.0,
        backgroundColor: Colors.black,
      ),
    );
  }
}

每当用户切换到会议列表组件时,我都会从 Firestore 获取数据。我不想那样做。相反,我想将各自的数据从 Home 传递到其他组件。它应该是快照,所以它可以监听变化。

MeetingList.dart

class MeetingList extends StatelessWidget {
  var userInfo;
  FirebaseAuth firebaseAuth = FirebaseAuth.instance;
  Future getuserinfo() async {
    // final uid = firebaseAuth.currentUser.uid;
    // userinfo = await firestoreService.getCurrentUserInfo(uid);
    // userinfo = userinfo.data().length;
    // //print(userinfo);
    // return uid;
    final uid = firebaseAuth.currentUser.uid;
    DocumentSnapshot user = await FirebaseFirestore.instance
        .collection('userProfiles')
        .doc(uid)
        .get();
    userInfo = user.data();
    return userInfo;
  }

  @override
  Widget build(BuildContext context) {
    CollectionReference meetings =
        FirebaseFirestore.instance.collection('meetings');
    return FutureBuilder(
      future: getuserinfo(),
      builder: (context, AsyncSnapshot snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return LoadingIndicator();
        } else {
          return StreamBuilder<QuerySnapshot>(
            stream: meetings.snapshots(),
            builder:
                (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
              if (snapshot.hasError) {
                return Text('Something went wrong');
              }

              if (snapshot.connectionState == ConnectionState.waiting) {
                return LoadingIndicator();
              }

              return new ListView(
                children: snapshot.data.docs.map((DocumentSnapshot document) {
                  String meetingRole = document.data()['role'];
                  var userRole = userInfo['role'];
                  print(userRole);
                  if (meetingRole == 'all' || meetingRole == userRole) {
                    return Meeting_Card(
                      meeting: document.data(),
                    );
                  } else {
                    return Container();
                  }
                }).toList(),
              );
            },
          );
        }
      },
    );
  }
}

您的帮助将对社区大有帮助。

【问题讨论】:

  • 您必须在Home 屏幕的initState 方法中获取所有API,并初始化您传递给setState 内的子小部件的所有变量。
  • @RaviSinghLodhi ,但我在 Home 小部件中调用的组件不接受数据。
  • @RaviSinghLodhi 不过,我会按照你说的尝试。
  • 你会把数据从Home.dart传递到MeetingList.dart吗?
  • 我做到了.. 我收到此错误The instance member 'meetings' can't be accessed in an initializer. Try replacing the reference to the instance member with a different expression

标签: android flutter google-cloud-firestore storage flutter-dependencies


【解决方案1】:

您可以为此使用 Provider 包,它是颤振中 InheritedWidget 的包装器。

InheritedWidget 用于有效地向下传播信息 树,而不必通过各种构造函数传递它们 在小部件树下。

你可以找到更多关于InheritedWidgethere的信息。

Provider 包是围绕InheritedWidget 进行包装的 更易于使用且可重复使用。

有关Provider 的更多信息,请参阅文档here

使用Provider 实施您的解决方案: 创建一个名为 UserProviderChangeNotifier 类来保存您希望在所有子小部件之间共用的数据:

class UserProvider extends ChangeNotifier {

  User userInfo;
  
  Future getuserinfo() async {
    // final uid = firebaseAuth.currentUser.uid;
    // userinfo = await firestoreService.getCurrentUserInfo(uid);
    // userinfo = userinfo.data().length;
    // //print(userinfo);
    // return uid;
    final uid = firebaseAuth.currentUser.uid;
    DocumentSnapshot user = await FirebaseFirestore.instance
        .collection('userProfiles')
        .doc(uid)
        .get();
    userInfo = user.data();
    return userInfo;
  }

}

现在将您的 Home 小部件包装在 ChangeNotifierProvider 小部件中:

class HomeScreen extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<UserProvider>(
      lazy: false,
      create: (context) => UserProvider(),
      child: Home(),
    );
  }

}

现在您可以使用以下方法从同一小部件​​树(任何选项卡) 的任何位置访问UserProvider 类的内容:

/// Get an instance of the UserProvider in the ancestors of the current widget tree like this.
UserProvider userProvider = Provider.of<UserProvider>(context);

/// Call any method inside the UserProvider class like this
userProvider.getUserInfo();

/// access any data variables inside the UserProvider class like this.
User userInfo = userProvider.userInfo;

您还可以查看提供程序包中的ConsumerSelector 小部件,它们提供了一种基于ChangeNotifier 类的某些参数重绘UI 的有效方法,当notifyListeners() 方法从ChangeNotifier 类调用。

【讨论】:

  • 感谢您的回答。这会有所帮助。
  • 我在要调用的 Home 小部件中创建了 UserProvider 的实例。当我初始化这个 --> UserProvider userProvider = Provider.of&lt;UserProvider&gt;(context);,我得到这个错误The instance member 'context' can't be accessed in an initializer.
  • 你在UserProvider userProvider = Provider.of&lt;UserProvider&gt;(context);initState()做这个吗?
  • 是的!我需要在构建之前以 init 状态调用它
  • 您可以将代码添加为问题本身的更新。顺便说一句,不需要初始化:UserProvider userProvider = Provider.of&lt;UserProvider&gt;(context); UserProvider 的实例已经在 ChangeNotifierProvidercreate() 中初始化。 Provider.of&lt;UserProvider&gt;(context) 只是为您提供对同一实例的引用。所以你可以在任何地方使用它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-24
  • 2021-07-02
  • 2021-04-23
  • 1970-01-01
  • 1970-01-01
  • 2022-01-16
相关资源
最近更新 更多