Provider: Provider in Navigation

Created on 24 Aug 2020  路  9Comments  路  Source: rrousselGit/provider

I have a use-case that got me a bit confused in the way I understood Provider or Navigation.

So I have two views with scoped Providers, which are StateNotifierProiders to be precise.

QuizView and SelectedQuizView
The quiz view has a list of tiles on selecting navigates to that selected information with more info. Now, on both of these, I am managing the state of favorites since they can be marked as a favourite or not favorite which should update in both thee views.

Since SelectedQuizView is inside of QuizView in the during navigation, I thought the StateNotifier, QuizVM which is scoped to QuizView should have been created and exists.

So I did what I thought was the most logical thing and did this

 StateNotifierProvider<QuizVM,QuizState>.value(
value: QuizVM
child SelectedQuizView( ) 

Since QuizVM was already created. Now I was able to access QuizVM but it seemed to be a new instance as the state was reverted to loading and I thought it should be Loaded since it was set in the previous view.

While at this I got another Exception DependencyNotFoundException from read<Repositiry> which made me even more confused because this Repository is a global Provider.

I solved this by a Workaround of making QuizVM a global Provider and giving SelectedQuizView its own StateNotifier.

But I'm curious as to what I was doing wrong. And would like to know. Can you please give me a better understanding?

Thank you!

bug

Most helpful comment

Instead you can have a StatefulWidget in your route and override its State.dispose to reset the model state:

class Model extends ChangeNotifier {
  int count =0;

  void reset() {
    count = 0;
  }
}


class Example extends StatefulWidget {
  @override
  _ExampleState createState() => _ExampleState();
}

class _ExampleState extends State<Example> {
  Model model;

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    model = context.watch<Model>();
  }

  @override
  Widget build(BuildContext context) {
    return Container();
  }

  @override
  void dispose() {
    model.reset();
    super.dispose();
  }
}

All 9 comments

@rrousselGit Can you please help me with this? I still have not been able to figure it out

Is your StateNotifierProvider above MaterialApp? That's usually the problem

@rrousselGit , No, My StateNotifierProvider was scoped to only one screen. Moving it above MaterialApp Solved my problem.

I wanted to access the same instance of StateNotifier that is Scoped to one screen, in another screen which in navigated to.

Which I tought I could by using StateNotifierProvider.value( ), I was able to but it was a different instance since the initial sate was set again, this is where I am stuck

I wouldn't recommend scoping providers to a route. That's very rarely a good idea.

@rrousselGit, I don't usually do, but for some views, I want the state to be reset when I pop the screen. So all the data is reset in that state the next time it's opened.
I had this problem when I had all my providers above MaterialApp. So I stuck to scoped providers.

Can you suggest an alternative if this isn't the best approach ?

Instead you can have a StatefulWidget in your route and override its State.dispose to reset the model state:

class Model extends ChangeNotifier {
  int count =0;

  void reset() {
    count = 0;
  }
}


class Example extends StatefulWidget {
  @override
  _ExampleState createState() => _ExampleState();
}

class _ExampleState extends State<Example> {
  Model model;

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    model = context.watch<Model>();
  }

  @override
  Widget build(BuildContext context) {
    return Container();
  }

  @override
  void dispose() {
    model.reset();
    super.dispose();
  }
}

Thanks. That's a good option.

But I try to avoid all the Statefull widget mess and use Hooks for any such use case of state.

Is there anyway I can achieve the same with useEffect() ? If so could you tell me more ?

I'm trying to figure out all the options.

sure:

final model = context.watch<Model>();
useEffect(() {
  return model.reset;
}, [model]);

@rrousselGit Thank you so much, I will try this out.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

hou3172568 picture hou3172568  路  4Comments

ykaito21 picture ykaito21  路  3Comments

jihongboo picture jihongboo  路  4Comments

prasadsunny1 picture prasadsunny1  路  6Comments

stocksp picture stocksp  路  5Comments