9

How do I access the value in a provider model from the init function or a workaround?

Basically, when my App loads, I save some value in a provider model.

One value is a search variable. Then I am redirected to a loading page where I need this value to get the data and render a list.

I am retrieving the data in the init method.

-- My Main function

void main() {
  runApp(
   Provider<UserModel>(
      builder: (_) => UserModel(),
      child: Jobs(),
    ),
  ); //added
}

This is a snippet of my Jobs page

case '/main':
   return MaterialPageRoute(
      builder: (_) => JobsHomePage(title: "jobs"));
   break;

This is list page that displays this list --- JobsHomePage()

void initState() {
    searchVal = Provider.of<UserModel>(context).searchVal;
    jb =load(searchVal);
}

Then I have a builder method that iterates thru 'jb' and prints the value

The error I am getting is inherited error

flutter: When an inherited widget changes, for example, if the value of Theme.of() changes, it's dependent

Thanks for your help... I did not post the entire code because it is very long and I get some "all code" error in the stack.

Phani Rithvij
  • 4,030
  • 3
  • 25
  • 60
user2570135
  • 2,669
  • 6
  • 50
  • 80
  • Same question https://stackoverflow.com/questions/60363665/dependoninheritedelement-was-called-before-initstate-in-flutter – Phani Rithvij Apr 28 '20 at 09:24

2 Answers2

39

The accepted answer by Mikhail is fine if you don't need to update the widget again after performing some task in the didChangeDependencies method. (Which is not the case most of the time.)

But it will not work if you need to notify the listeners after performing the task.

The context is accessible in initState. You need to add the argument listen: false to the Provider.

The docs say

listen: false is necessary to be able to call Provider.of inside [State.initState] or the create method of providers like so: ...

  @override
  void initState() {
    super.initState();
    final _store = Provider.of<RecorderStore>(context, listen: false);
  }

Now as to why overriding didChangeDependencies is not a good idea:

In the docs it says

For example, if the previous call to build referenced an InheritedWidget that later changed, the framework would call this method to notify this object about the change.

Therefore when you use ChangeNotifierProvider for example, when you call notifyListeners() that will call the didChangeDependencies method.

So when you call notifyListeners through didChangeDependencies it will lead to an infinite loop.

Or even if you don't call notifyListeners explicitly, whenever the didChangeDepencies method is called, the code is executed multiple times.

So better to use listen: false in the initState to ensure that the code is executed only once.

Phani Rithvij
  • 4,030
  • 3
  • 25
  • 60
  • 2
    Thank you, I had the same problem. I have store which should take singleton dependencies in constructor and using didChangeDependencies trigger continuous rebuilds. Using `listen: false` solved the problem – MatPag May 14 '20 at 10:02
  • 2
    This is a great answer. This should be marked as accepted answer. I have been passing parameters the conventional way when I needed the value from provider. That was redundant. This solves my problem a great deal – Vinayakaram Nagarajan Jun 04 '20 at 14:12
  • I get a null error because Provider takes a tick to populate, and doing a null check doesn't work in initstate...how to use the value? – jbryanh Feb 19 '21 at 20:10
  • @PhaniRithvij What should we do if we have to notify the listeners and have to call provider in initState? – Davoud Sep 04 '21 at 19:49
  • @Patzu I think you can do a `notifyListeners()` as you normally would? – Phani Rithvij Sep 07 '21 at 09:16
5

You can't access context in initState, but you can access it in didChangeDependencies.
According to offical docs it's called right after initState and it can use context, so it can call Provider.of<T>(context)

Mikhail Ponkin
  • 2,563
  • 2
  • 19
  • 19