stream builder is not updating after navigation

2,045

Your conditional Is not being tested in the sub page. You should call Provider.of in the sectionWrapper() page.

You’re saying:

  • if user is logged in, build sectionWrapper widget
  • if user is not logged in build Authentication widget.

That is it for that build method. Once that is built, you need to say what you want to do next.

Eg. On the next screen, above your widget tree, set provider.of like you did. Then, if the value changes, provider will force a rebuild for that screen’s build method.

Share:
2,045
Ali Alqallaf
Author by

Ali Alqallaf

Updated on December 23, 2022

Comments

  • Ali Alqallaf
    Ali Alqallaf over 1 year

    I am using a stream builder to detect if user logged in or not.

     return StreamBuilder<User>(
            stream: AuthService().user,
            builder: (context, snapshot) {
              if (snapshot.hasData)
                return SectionWrapper();
              else
                return Authentication();
            });
    

    and this is the stream I am using

     Stream<User> get user {
        return _auth.onAuthStateChanged.map(_userFromFirebaseUser);
      }
      //create user object based on firebase user
      User _userFromFirebaseUser(FirebaseUser user) {
        return user != null ? User(uid: user.uid, email: user.email) : null;
      }
    

    in the section wrapper, there are 2 buttons that navigates to two different sections of the app, when I use sign out method in one of these sections, the stream builder is not updating, and it requires refresh to update the state.

    also i tried to put a button in section wrapper to sign out, it works and update UI before I navigate to one of the sections.

    and this is the sectionWrapper() widget tree.

    Column(
            children: <Widget>[
              CupertinoButton(
                  child: Text('Donation & Selling Section'),
                  onPressed: () {
                    Navigator.pushReplacementNamed(
                        context, Section1.routeName,
                        arguments: user);
                  }),
              CupertinoButton(
                  child: Text('Bookstores Section'),
                  onPressed: () {
                    Navigator.pushReplacementNamed(
                        context, Section2.routeName);
                  }),
              
              //works before navigation, does not work after navigation back here
              CupertinoButton(
                  child: Text('Sign out'),
                  onPressed: () async {
                    await AuthService().signOut();
                  }),
            ],
          ),
    

    I also tried to use stream provider with consumer and I ended with the same problem.

       class Wrapper extends StatelessWidget {
      static const String routeName = '/';
    
      @override
      Widget build(BuildContext context) {
        final user = Provider.of<User>(context);
        return user == null ? Authentication() : SectionWrapper();
      }
    }
    

    I wrapped material app with a stream provider.

    MultiProvider(
          providers: [
            StreamProvider<User>.value(value: AuthService().user),
    //other providers
          ],
          child: MaterialApp(
    
    • lenz
      lenz over 3 years
      You should probably use stream provider for this.
    • Ali Alqallaf
      Ali Alqallaf over 3 years
      I tried and I kept getting the same result
    • lenz
      lenz over 3 years
      Streambuilder has more boilerplate. You probably need to check for errors and connection state and such like this example from the docs. I’m not surprised this isn’t working.
    • lenz
      lenz over 3 years
      StreamProvider will work 100%. I am doing the same thing. Are you placing the provider high enough in the widget tree? Could you share your code with streamProvider? And indicate where you put the provider?
    • Ali Alqallaf
      Ali Alqallaf over 3 years
      I edited the question and share the code, i think it is high enough unless I should pass some data when navigate. Please take a look
    • lenz
      lenz over 3 years
      Ah I see what’s going on. You’re wanting the user to be redirected to Authentication() when they sign out from the SecrionWrapperscreen correct?
    • lenz
      lenz over 3 years
      Check out my answer, that should fix your issue. Please accept it if it helps. Or let me know if it doesnt
  • Ali Alqallaf
    Ali Alqallaf over 3 years
    It did work! I have been struggling for about 3 weeks, and you helped me. thank you so much I really appreciate it!
  • lenz
    lenz over 3 years
    Fantastic! I’m happy I could help, thanks for the message. Please upvote too :)
  • Ali Alqallaf
    Ali Alqallaf over 3 years
    when i tried your solution, it works fine, but when I sign in again with another user, i get back to the point where i logged out, the problem is when i make an action, all actions happen with the previous user despite the difference of the user id until i refresh the page using navigator or something to fetch data again, so is there any way to go to section wrapper when signing out so that when i sign back in, the section wrapper occurs and when I navigate to a section, data get fetched again
  • lenz
    lenz over 3 years
    That seems like a business logic issue my friend. It's hard to be more precise without seeing the rest of your code, but basically: provider will rebuild the page you're on when the user changes. So at the top of that page, withing your build method, you want to do the logic, i.e. if user is null go to Authentication. You might also want to revisit how you navigate between screens with Navigator.
  • lenz
    lenz over 3 years
    Ultimately, it is not the same issue. You should ask another question for this