Provider: Allow context.watch in didChangeDependencies

Created on 18 Jun 2020  ยท  13Comments  ยท  Source: rrousselGit/provider

Problem

In some cases, I want to update a value in a State both inside of the state itself and also when dependencies change.
This makes it attractive to use context.watch inside of didChangeDependencies.

Solution

I would like to be able to use context.watch inside of didChangeDependencies.

@override
void didChangeDependencies() {
  super.didChangeDependencies();

  _value = context.watch<Value>();
}

Workaround

@override
void didChangeDependencies() {
  super.didChangeDependencies();

  _value = Provider.of<Value>(context);
}
enhancement

Most helpful comment

This will change soon enough when I'm done with a linter for provider. In which case read/watch will be allowed everywhere but will trigger a warning when misused

All 13 comments

You can do that operation inside build.
didChangeDependencies doesn't bring anything special

It is crucial to me that the value is not updated with every build, though.

Basically, I want to update the value in the state itself and only override it when the dependency actually changes. ๐Ÿ™ƒ
I can make that work in build as well by storing another variable in the state, but that is not optimal, or is it?

It is crucial to me that the value is not updated with every build, though.

Why so?

I explained it: I want to use a state internal value unless the dependency changes. If I want to use context.watch in build, I would need to store the previous dependency value as well ๐Ÿ˜ถ

I would need to store the previous dependency value as well ๐Ÿ˜ถ

You need to anyway. didChangeDependencies does not guarantee that the value you are reading has changed.
It is called anytime any dependency changed or on a relocation of the element using GlobalKey.

You cannot use didChangeDependencies to know if a specific dependency changed unless you guarantee that your widget will always forever have a single dependency.
That's feasible for some use-cases, but is very brittle and it would be a lot more reasonable to store the previous value and do a if (previous != new) โ€“ which you can do inside build too.

In my case I am sure, but you are right of course - it is safer to store it.

I feel like it is also syntactically/semantically nice to separate the functions, however ๐Ÿ™ƒ

You could do:

Widget build(context) {
  _didChangeDependencies();
 ... 
}

I guess I meant on a framework/architecture level ๐Ÿ˜‚

The readme on:

https://pub.flutter-io.cn/packages/provider

Says you should do exactly this and I just refactored my code to try to as I am doing something which always causes a change in the state of an object between reading it in initState and reading it in build(). I had been doing if (!identical(saved_object, received_object)) inside of the build method but I tried to tidy up my code as I know you're not supposed to modify state in the build method and I have to when the object changes.

As I'm here to report the discrepancy with the readme, what's the right way to deal with this since you're not supposed to modify state in the build method? I don't see any reason I shouldn't change the state in this instance other than convention since it will only happen when the object changes but I'm a newbie I could be completely wrong?

I fixed the readme. You can use build instead. It'll work the same

It is not the same. However, I guess we need to live with that regression for the sake of the extension.

This will change soon enough when I'm done with a linter for provider. In which case read/watch will be allowed everywhere but will trigger a warning when misused

Yes, I heard about that in your podcast episode :)

Was this page helpful?
0 / 5 - 0 ratings