Search code examples
flutterflutter-providerflutter-state

Why Provider.of<> doesn't work without `listen: false`?


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?


Solution

  • 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