Provider: Doubt with Provider.of

Created on 14 Mar 2019  路  15Comments  路  Source: rrousselGit/provider

Hello, nice library 馃榾.
can you explain me please what is the difference.

Provider.of<SomeClass>(context, listen: true)
Provider.of<SoomeClass>(context, listen: false)

I noticed that I can use in initState() of StatefulWidget when is false, and can't use when is true, but really I don't know why :(

Thanks

documentation

Most helpful comment

listen determines if the widget that use the value wants to rebuild when the value change.

For example, if:

Provider<int>(
  value: 42,
 child: ...
)

is later replaced by:

Provider<int>(
  value: 24,
  child: ...

Then this will trigger a rebuild of all widgets that called Provider.of(context) with listen to true.

All 15 comments

listen determines if the widget that use the value wants to rebuild when the value change.

For example, if:

Provider<int>(
  value: 42,
 child: ...
)

is later replaced by:

Provider<int>(
  value: 24,
  child: ...

Then this will trigger a rebuild of all widgets that called Provider.of(context) with listen to true.

Hi @rrousselGit, is it the way to update the value in a stateful widget?
For example:

Provider<int>(
  value: _value,
  child: ...
)

...
// Some widget calls (e.g. onClick event)
setState({
  _value = 1234,
})


Yes, that's how you should do it.

@rrousselGit thank you for your confirmation! However, I'm stuck with this for quite long, not sure which part of my codes are wrong.

For example:
App init provider value as 123.
In Screen A, a button update the provider value to 456.
However, in screen B, it return the provider value as 123 instead of 456.

App:

MultiProvider(
  providers: [
    Provider<int>(
      value: 123,
      child: MaterialApp(
      ...
      ),
    ),
    ... // other providers
  ],
)

Screen A:

... 
int _value = 0;
...

Widget build(BuildContext context) {
  return Provider.of<int>(
    value: _value,
    child: Scaffold(
      ...
      Button(
        onPressed: ()  {
          setState({
            _value = 456, // Set value to 456
          });
        }
      ),
    ),
  );
}

Screen B:

int _value;

Widget build(BuildContext context) {
  final _provider = Provider.of<int>(context);
  // when access _provider, the value still returns 123 instead of 456
}

It looks to me that you have two provides: one in the App and one in Screen A. The value you got in Screen B is from the App, which is a value literal of 123.

@enetor Initially, Screen A is supposed to change the value in Provider by doing setState({ value = 456 }). :(

@enetor @rrousselGit Do you have recommendation on how to update the value from Screen A?

hi, what if we are using ChangedNotifierProvider? will it based on the notifiedListener, instead of value changed? and i suppose it will not rebuild if listen = false right?

It seems listen parameter is not working in my example, whenever I call setState, it will just rebuild the child widget no matter listen is false or not. Am I doing something wrong? @rrousselGit

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
          // Center is a layout widget. It takes a single child and positions it
          // in the middle of the parent.
          child: Provider<int>.value(
              value: _counter,
              child: Column(
                children: <Widget>[TestStatelessWidget()],
              ))),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        child: Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

class TestStatelessWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // result is updated anyway, listen = false does not work.
    int result = Provider.of<int>(context, listen: false);
    return Text("result: $result");
  }
}

@PandaGeek1024

This should work.
Without const, TestStatelessWidget's rebuild is triggered by State's setState even though listen = false.
listen = false just suppresses rebuild triggered by Provider not State's setState.

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
          // Center is a layout widget. It takes a single child and positions it
          // in the middle of the parent.
          child: Provider<int>.value(
              value: _counter,
              child: Column(
                // add `const`
                children: const <Widget>[TestStatelessWidget()],
              ))),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        child: Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

class TestStatelessWidget extends StatelessWidget {
  // add `const` constructor
  const TestStatelessWidget();
  @override
  Widget build(BuildContext context) {
    // result is updated anyway, listen = false does not work.
    int result = Provider.of<int>(context, listen: false);
    return Text("result: $result");
  }
}

Exactly

Which is also why provider love const constructors/statelesswidgets

Hey @rrousselGit and @mono0926,

I am having a similar issue to @PandaGeek1024 except that my app (in the following attached document) uses only StatelessWidgets so there is no call to setState anywhere.

Listen doesn't work.txt

For that reason, I am not sure what is causing my text widgets to rebuild themselves.

I have been trying to figure this out for 2 days now so any insight you could give would be much appreciated.

@Wes1324

This should work.

         TextField(
            onChanged: (newText) {
              Provider.of<Data>(context, listen: false).updateValue(newText);
            },
          )

@mono0926
Please can you explain why this works?
Thank you

@Wes1324
I wrote about that in this article. This is written in Japanese, sorry.
https://link.medium.com/7a5FrRXFw0

I believe that the new syntax (context.read/watch) makes it clear enough for this issue to be closed.

Feel free to correct me if you disagree

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tmxdyf picture tmxdyf  路  3Comments

ykaito21 picture ykaito21  路  3Comments

arnoutvandervorst picture arnoutvandervorst  路  4Comments

prasadsunny1 picture prasadsunny1  路  6Comments

jihongboo picture jihongboo  路  4Comments