Flutter:如何从子Widget设置父Widget的状态

5

我对Flutter和Dart非常初学。所以我试图更新父小部件的状态,但说实话,在尝试了许多不同的解决方案后,没有一个适用于我,或者我做错了什么吗?

我想要做的是在_Books()类中更改页面时更新_BooksState()中的_title

我该如何从子(_Books())小部件设置_title状态?

class Books extends StatefulWidget {
  @override
  _BooksState createState() {
    return _BooksState();
  }
}

class _BooksState extends State<Books> {
  String _title = 'Books';

  _setTitle(String newTitle) {
    setState(() {
      _title = newTitle;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(_title),
      ),
      body: _Books(),
    );
  }
}

class _Books extends StatelessWidget {
  final PageController _controller = PageController();
  final Stream<QuerySnapshot> _stream =
      Firestore.instance.collection('Books').orderBy('title').snapshots();

  _setAppBarTitle(String newTitle) {
    print(newTitle);
    // how do I set _title from here?
  }

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<QuerySnapshot>(
      stream: _stream,
      builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
        final books = snapshot.data.documents;
        switch (snapshot.connectionState) {
          case ConnectionState.waiting:
            return Center(child: CircularProgressIndicator());
          default:
            return PageView.builder(
              controller: _controller,
              scrollDirection: Axis.horizontal,
              itemCount: books.length,
              itemBuilder: (context, index) {
                final book = books[index];
                return ListTile(
                  title: Text(book['title']),
                  subtitle: Text(book['author']),
                );
              },
              onPageChanged: (index) {
                _setAppBarTitle(books[index].data['title']);
              },
            );
        }
      },
    );
  }
}
2个回答

1
让我换一种方式重复你的问题:当某些事情发生时(不在小部件的同一类中),您想要设置小部件状态(或刷新页面,或更改绑定到小部件的变量)。
这是Flutter中所有新手(包括我)的常见问题,称为状态管理。
当然,您可以始终将所有内容放在同一个Dart文件中,甚至是同一个类中,但对于较大的应用程序,我们不会这样做。
为了解决这个问题,我创建了两个示例:
  1. https://github.com/lhcdims/statemanagement01
这个示例使用定时器来检查小部件内部是否有变化,如果有,则设置小部件所属页面的状态。请查看main.dart中的funTimerDefault()函数。
好的,这是我的第一次尝试,不是一个好的解决方案。
  1. https://github.com/lhcdims/statemanagement02
这个例子的输出与1相同,但使用的是Redux而不是setState。早晚你会发现,setState并不适用于所有情况(比如你的情况!),你将使用Redux或BLoC。
阅读示例中的自述文件,构建和运行它们,然后您就可以随时(在任何地方)刷新任何小部件(或更改绑定到小部件的变量)。即使应用程序被推到后台,您也可以在示例中尝试此操作。

Redux链接已损坏。 - davaus
请查看 https://github.com/lhcdims/statemanagement01/blob/master/lib/main.dart 的第51行,问题已被修复。 - Mahesh Jamdade

0
你可以将你的 _Books 类移动到 _BooksState 类内部。 并且,不再使用 _Books 作为类,而是在 _BooksState 类内部使用它作为 Widget,这样你就可以在创建的 Widget 内部访问 StatefulWidgetsetState 方法。
我以这种方式做,即使我是 Flutter 和 Dart 的新手... 在每种情况下都能正常工作,即使在调用 API 后... 我也能使用 setState 并设置来自 API 的响应。 示例:
class Books extends StatefulWidget {
  @override
  _BooksState createState() {
    return _BooksState();
  }
}

class _BooksState extends State<Books> {
  String _title = 'Books';

  _setTitle(String newTitle) {
    setState(() {
      _title = newTitle;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(_title),
      ),
      body: _books(), // Using the Widget here
    );
  }

  // Your `_Books` class created as `Widget` for setting state and new title.
  Widget _books() {
    final PageController _controller = PageController();
    final Stream<QuerySnapshot> _stream =
    Firestore.instance.collection('Books').orderBy('title').snapshots();

    _setAppBarTitle(String newTitle) {
      print(newTitle);
      // how do I set _title from here?

      // Since you created this method and setting the _title in this method 
      // itself using setstate you can directly pass the new title in this method..
      _setTitle(newTitle);
    }

    return StreamBuilder<QuerySnapshot>(
      stream: _stream,
      builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
        final books = snapshot.data.documents;
        switch (snapshot.connectionState) {
          case ConnectionState.waiting:
            return Center(child: CircularProgressIndicator());
          default:
            return PageView.builder(
              controller: _controller,
              scrollDirection: Axis.horizontal,
              itemCount: books.length,
              itemBuilder: (context, index) {
                final book = books[index];
                return ListTile(
                  title: Text(book['title']),
                  subtitle: Text(book['author']),
                );
              },
              onPageChanged: (index) {
                _setAppBarTitle(books[index].data['title']);
              },
            );
        }
      },
    );
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接