Provider: Why does Provider.of( listen: false) will still trigger the widget rebuild?

Created on 18 Jun 2020  Â·  10Comments  Â·  Source: rrousselGit/provider

Most helpful comment

The documentation is really clear about how Consumer and Provider.of work with and without listen flag.

You can use these samples using both ways.


class SampleProvider extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => Counter()),
      ],
      child: MyHomePage(),
    );
  }
}

Using Provider.of and listen:true (by default).

~ Every time you call increment method its rebuild all the widget.


class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final counter = Provider.of<Counter>(context);
    print('build $this');
    return Scaffold(
      appBar: AppBar(
        title: const Text('Example'),
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text('You have pushed the button this many times:'),
            Text(
              counter.count.toString(),
              style: Theme.of(context).textTheme.headline5,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => counter.increment(),
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

Using Consumer and listen:false.

~ Every time you call the increment method, only the widget is rebuilt within the Consumer.

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print('build $this');
    final counter = Provider.of<Counter>(context, listen: false);
    return Scaffold(
      appBar: AppBar(
        title: const Text('Example'),
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text('You have pushed the button this many times:'),
            Consumer<Counter>(
              builder: (_, value, __) {
                print('build consumer $this');
                return Text(
                  value.count.toString(),
                );
              },
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => counter.increment(),
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

Check the print statements I added and see how it shows.

All 10 comments

I don't understand. Are you expecting Consumer not to be called again?

@rrousselGit
Yes, I am expecting Consumer not to be called, for I don't want the Widget to rebuild again, I just want to delete data in the background.

According the doc, when listen is set false, it won’t cause this widget to rebuild when notifyListeners is called.

Since the doc I mentioned above is related to the tutorial about state management involving Consumer, ChangeNotifier and ChangeNotifierProvider, I expect that the builder callback method in Consumer won't be triggered.

Am I right? Thanks.

I don't understand. Are you expecting Consumer not to be called again?

Consumer doesn't have a "listen" flag. It is unrelated to Provider.of

@rrousselGit
Yes, I am expecting Consumer not to be called, for I don't want the Widget to rebuild again, I just want to delete data in the background.

According the doc, when listen is set false, it won’t cause this widget to rebuild when notifyListeners is called.

Since the doc I mentioned above is related to the tutorial about state management involving Consumer, ChangeNotifier and ChangeNotifierProvider, I expect that the builder callback method in Consumer won't be triggered.

Am I right? Thanks.

I don't understand. Are you expecting Consumer not to be called again?

You can think of Consumer as Provider.of (contxt,true),
notify will cause it to build()

You can think of Consumer as Provider.of (contxt,true),
notify will cause it to build()

@Zengyonghao Actually, I can't find the difference between Provider.of(context,false) and Provider.of(Cotext.true), since I see both will trigger the rebuild of widget(Not Consumer, I mean normal widgets, such as Text), I am expecting Provider is used to rebuild on-demand for widget apart from providing app level state.

The documentation is really clear about how Consumer and Provider.of work with and without listen flag.

You can use these samples using both ways.


class SampleProvider extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => Counter()),
      ],
      child: MyHomePage(),
    );
  }
}

Using Provider.of and listen:true (by default).

~ Every time you call increment method its rebuild all the widget.


class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final counter = Provider.of<Counter>(context);
    print('build $this');
    return Scaffold(
      appBar: AppBar(
        title: const Text('Example'),
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text('You have pushed the button this many times:'),
            Text(
              counter.count.toString(),
              style: Theme.of(context).textTheme.headline5,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => counter.increment(),
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

Using Consumer and listen:false.

~ Every time you call the increment method, only the widget is rebuilt within the Consumer.

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print('build $this');
    final counter = Provider.of<Counter>(context, listen: false);
    return Scaffold(
      appBar: AppBar(
        title: const Text('Example'),
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text('You have pushed the button this many times:'),
            Consumer<Counter>(
              builder: (_, value, __) {
                print('build consumer $this');
                return Text(
                  value.count.toString(),
                );
              },
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => counter.increment(),
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

Check the print statements I added and see how it shows.

Closing as this is working as expected – Consumer always listens to changes in the object

Then what the point of listen=false?

Then what the point of listen=false?

The point is not to listen to the values values, only to have access to the providers.

Then what the point of listen=false?

It prevents rebuilds caused by the specific provider you are reading. But the widget will still rebuild from other sources

Was this page helpful?
0 / 5 - 0 ratings