简体   繁体   English

Flutter:从子小部件设置父小部件状态

[英]Flutter: set parent widget state from child widget

I am very beginner to Flutter and Dart.我是 Flutter 和 Dart 的初学者。 So I am trying to update the state of the parent widget, but to be honest after trying many different solutions none worked for me, or am I doing something wrong?所以我试图更新父小部件的状态,但说实话,在尝试了许多不同的解决方案后,没有对我有用,还是我做错了什么?

What I'm trying to do is to update the _title in _BooksState() when the page changes in _Books() class.我正在试图做的是当页面中_Books()类的变化来更新_BooksState()的_title。

How do I set the _title state from the child (_Books()) widget?如何从子 (_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']);
              },
            );
        }
      },
    );
  }
}

let me repeat your question in other words: You want to setstate a widget(or refresh a page, or change a variable 'binded' to a widget) when something happens(not inside the same class of the widget).让我重复您的问题,换句话说:您想在发生某些事情时(不在小部件的同一类内)设置状态小部件(或刷新页面,或将变量“绑定”到小部件)。

This is a common problem for all newbies in flutter(including me), which is called state management.这是flutter所有新手(包括我)的通病,就是状态管理。

Of course you can always put everything inside the same dart file, or even the same class, But we don't do that for larger app.当然,您始终可以将所有内容都放在同一个 dart 文件中,甚至同一个类中,但是对于较大的应用程序,我们不会这样做。

In order to solve this problem, I created 2 examples:为了解决这个问题,我创建了2个例子:

  1. https://github.com/lhcdims/statemanagement01 https://github.com/lhcdims/statemanagement01

This example uses a timer to check whether something inside a widget is changed, if so, setstate the page that the widget belongs to.此示例使用计时器来检查小部件内的某些内容是否已更改,如果是,则设置状态小部件所属的页面。

try to take a look at the function funTimerDefault() inside main.dart试着看看 main.dart 里面的函数 funTimerDefault()

Ok, this was my first try, not a good solution.好的,这是我的第一次尝试,不是一个好的解决方案。

  1. https://github.com/lhcdims/statemanagement02 https://github.com/lhcdims/statemanagement02

This example's output is the same as 1, But is using Redux instead of setState.此示例的输出与 1 相同,但使用的是 Redux 而不是 setState。 Sooner or later you'll find that setstate is not suitable for all cases(like yours!), you'll be using Redux or BLoC.迟早你会发现 setstate 并不适合所有情况(就像你的一样!),你会使用 Redux 或 BLoC。

Read the readme inside the examples, build and run them, you'll then be able to (refresh) any widget(or changes variables binded to a widget), at any time(and anywhere) you want.阅读示例中的自述文件,构建并运行它们,然后您将能够(刷新)任何小部件(或更改绑定到小部件的变量),在任何时间(和任何地方)您想要。 (even the app is pushed into background, you can also try this in the examples) (即使应用程序被推入后台,您也可以在示例中尝试)

What you can do is move you _Books class inside the _BooksState class.. And instead of using _Books as class you can use it as Widget inside _BooksState class so that you can access the setState method of StatefulWidget inside the Widget you create.您可以做的是将您的_Books类移动到_BooksState类中。而不是使用_Books作为类,您可以将其用作_BooksState类中的Widget以便您可以访问您创建的WidgetStatefulWidgetsetState方法。

I do it this way and even I'm new to Flutter and Dart...This is working for me in every case even after making an API call..I'm able to use setState and set the response from API.我是这样做的,即使我是 Flutter 和 Dart 的新手......即使在进行 API 调用后,这对我来说在任何情况下都有效......我能够使用setState并设置来自 API 的响应。

Example:例子:

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']);
              },
            );
        }
      },
    );
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM