0

I've simple widget tree, and try to figure out why Provider.of<>() doesn't work in the GestureDetector, onTap() callback.

This is my model:

class ShareObject {
  int intField;

  ShareObject(this.intField);
}

class ShareObjectProvider extends ShareObject with ChangeNotifier {
  ShareObjectProvider(super.intField);

  void increment() {
    intField++;
    notifyListeners();
  }
}

Here is my simple tree, where I try to invoke method from model:

class ParentWidgetState extends State<ParentWidget> {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (context) => ShareObjectProvider(0),
      child: Scaffold(
        body: const WidgetThree(),
      ),
    );
  }
}

class WidgetThree extends StatelessWidget {
  const WidgetThree({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Center(
      child: SizedBox(
        width: 200,
        height: 200,
        child: Container(
          color: Colors.deepOrange,
          child: Center(
              child: GestureDetector(
                onTap: () =>
                    {Provider.of<ShareObjectProvider>(context).increment()},
                child: Text(
                  "Test ${Provider.of<ShareObjectProvider>(context).intField}",
                  style: const TextStyle(color: Colors.blueAccent),
                ),
            )
          ),
        ),
      ),
    );
  }
}

Why when I change to Provider.of<ShareObjectProvider>(context, listen: false).increment() it start working correctly?

wapn
  • 359
  • 1
  • 7
  • 19

2 Answers2

0

Your syntax is not good for provider. you need to add listen : true OR listen: false.

Provider.of<ShareObjectProvider>(context, listen: false).increment()
Rohan Jariwala
  • 1,564
  • 2
  • 7
  • 24
  • With listen: false I get runtime exception `"Tried to listen to a value exposed with provider, from outside of the widget tree. This is likely caused by an event handler (like a button's onPressed) that called\nProvider.of without passing `listen: false`.\n\nTo fix, write:\nProvider.of(context, listen: false); It is unsupported because may pointlessly rebuild the widget associated to the event handler, when the widget tree doesn't care about the value.The context used was: WidgetThree(dependencies: [_InheritedProviderScope])"` And the question is why? – wapn Sep 06 '22 at 14:55
0

As per documentation,

Provider.of<T>(context)

works like a watch, which makes the widget to rebuild again

listen: false

makes it work like read

in your case:

late ShareObjectProvider provider;


void initState() {
  super.initState();

  provider = Provider.of<ShareObjectProvider>(listen: false);
}

then use it in your GestureDetector

here's the link for provider's documentation where the above said things are mentioned

iamdipanshus
  • 492
  • 3
  • 12
  • Thank you for link to documentation. Now I figured out what was wrong. The `onTap` callback is outside the widget tree. `It's worth noting that context.read() won't make a widget rebuild when the value changes and it cannot be called inside StatelessWidget.build/State.build. On the other hand, it can be freely called outside of these methods.` – wapn Sep 07 '22 at 08:38