简体   繁体   中英

Flutter: set parent widget state from child widget

I am very beginner to Flutter and 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.

How do I set the _title state from the child (_Books()) widget?

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.

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.

In order to solve this problem, I created 2 examples:

  1. 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

Ok, this was my first try, not a good solution.

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

This example's output is the same as 1, But is using Redux instead of setState. Sooner or later you'll find that setstate is not suitable for all cases(like yours!), you'll be using Redux or 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.

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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