PersistentBottomNavBarV2 icon indicating copy to clipboard operation
PersistentBottomNavBarV2 copied to clipboard

How to always refresh Nav Items when navigation to them?

Open leossmith opened this issue 3 years ago • 3 comments

Is there a way to always refresh (run initState) when I am navigation back to one of the Bottom Nav items?

Example: I am in Tab1 then navigate deeper to another screen. When I pop the second screen I want the tab1 to refresh.

leossmith avatar Jun 12 '22 12:06 leossmith

I think the widget lifecycle is not designed to make it possible to call initState on a widget that is already initialized. You could extract the thing that should happen into a method and pass that method as a callback to your second screen. Or can you share your specific case?

jb3rndt avatar Jun 21 '22 16:06 jb3rndt

So I am building an app that is a social network. There are 4 bottom tabs for navigating in the 4 main screens.

1st tab is the activity (list of posts) and from there I can navigate to a new screen "New Post" to publish something. Once I publish some new content, navigation takes me back to 1st tab 1st screen. At this point the activity should refresh to get all the new data from the server.

However I don't see any ways to setState or re initialize this screen.

leossmith avatar Jun 28 '22 09:06 leossmith

Ok I'll just put some pseudocode here to explain how I would tackle this issue:

You have your list of posts PostList and CreatePost. In CreatePost you probably have a button that calls a method for publishing the post publish. So if you give CreatePost a callback like that:

class CreatePost extends StatelessWidget {
  final VoidCallback onPublished;

  const CreatePost({ Key? key, this.onPublished }) : super(key: key);

  void publish() {
    // Save Post to server
    // Pop screen
    this.onPublished?.call();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      child: ElevatedButton(child: Text("Publish"), onPressed: publish,)
    );
  }
}

The callback onPublished will be executed after the post is published and the screen has been popped.

So in your PostList you can pass the callback to the CreatePost screen and say what should happen. I suppose you use a Futurebuilder for loading your posts.

class PostList extends StatefulWidget {
  const PostList({Key? key}) : super(key: key);

  @override
  State<PostList> createState() => _PostListState();
}

class _PostListState extends State<PostList> {
  Future postsFuture;

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

  void loadPosts() {
    postsFuture = http.get("example.com/posts");
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        ElevatedButton(
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(
                builder: (context) => CreatePost(
                  onPublished: () {
                    setState(() {
                      loadPosts();
                    });
                  },
                ),
              ),
            );
          },
          child: Text("Create Post"),
        ),
        FutureBuilder(
          future: postsFuture,
          builder: (context, snapshot) {
            if (snapshot.hasData) {
              return ListView(
                children: snapshot.data,
              );
            }
            return CircularProgressIndicator();
          },
        ),
      ],
    );
  }
}

So what should happen is that loadPosts re-initializes the future for loading the posts. And that is done as soon as a post is published because it is passed to CreatePost and then executed there. so when you get back to PostList the posts should reload. I hope that works?

jb3rndt avatar Jul 01 '22 18:07 jb3rndt