简体   繁体   中英

Flutter Provider.of<> without a consumer don't change my state

I am trying to get into the provider topic, however calling a function only works if I put it into a consumer

@override
Widget build(BuildContext context) {
return MultiProvider(
    providers: [
      ChangeNotifierProvider(create: (_) => ClickerProvider()),
    ],
    child: Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Text("some text"),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => Provider.of<ClickerProvider>(context, listen: false)
                          .incrementCounter(),
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    ));
}

As in this example, my state is not updated. However, it already works with a consumer.

floatingActionButton: Consumer<ClickerProvider>(
builder: (context, value, child) {
  return FloatingActionButton(
    onPressed: Provider.of<ClickerProvider>(context, listen: false)
        .incrementCounter,
    tooltip: 'Increment',
    child: Icon(Icons.add),
  );
},
)

Is there an error in my code?

As you can refer in the source code of Consumer here:

Obtains [Provider] from its ancestors and passes its value to [builder].

The [Consumer] widget doesn't do any fancy work. It just calls [Provider.of] in a new widget, and delegates its build implementation to [builder].

Provider.of<X> depends on value of listen ( true or false ) to trigger new State.build() to widgets and State.didChangeDependencies() for StatefulWidget .

Consumer<X> always update UI, as it uses Provider.of<T>(context) , where listen is true

In this case, since your listen is set as false, but you're putting it in the Consumer which make it true . That's why the UI will update with Consumer

You can copy paste run two full code below
Reason: Can not find ClickerProvider
Solution 1: Move ClickerProvider to upper level such as MyApp

class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MultiProvider(
            providers: [
              ChangeNotifierProvider(create: (_) => ClickerProvider()),
            ],
            child: MaterialApp(

Solution 2: Use Builder

body: Center(child: Builder(builder: (BuildContext context) {
                return Text(context.watch<ClickerProvider>().getCounter.toString());
              })),
floatingActionButton: Builder(builder: (BuildContext context) {
    return FloatingActionButton(
      onPressed: () =>
          Provider.of<ClickerProvider>(context, listen: false)
              .incrementCounter(),
      tooltip: 'Increment',
      child: Icon(Icons.add),
    );

full code 1

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class ClickerProvider extends ChangeNotifier {
  int _count = 0;

  int get getCounter {
    return _count;
  }

  void incrementCounter() {
    _count += 1;
    notifyListeners();
  }
}

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
        providers: [
          ChangeNotifierProvider(create: (_) => ClickerProvider()),
        ],
        child: MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: MyHomePage(title: 'Flutter Demo Home Page'),
        ));
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: Center(
          child: Text(context.watch<ClickerProvider>().getCounter.toString()),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () => Provider.of<ClickerProvider>(context, listen: false)
              .incrementCounter(),
          tooltip: 'Increment',
          child: Icon(Icons.add),
        ));
  }
}

full code 2

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class ClickerProvider extends ChangeNotifier {
  int _count = 0;

  int get getCounter {
    return _count;
  }

  void incrementCounter() {
    _count += 1;
    notifyListeners();
  }
}

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
        providers: [
          ChangeNotifierProvider(create: (_) => ClickerProvider()),
        ],
        child: Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: Center(child: Builder(builder: (BuildContext context) {
            return Text(context.watch<ClickerProvider>().getCounter.toString());
          })),
          floatingActionButton: Builder(builder: (BuildContext context) {
            return FloatingActionButton(
              onPressed: () =>
                  Provider.of<ClickerProvider>(context, listen: false)
                      .incrementCounter(),
              tooltip: 'Increment',
              child: Icon(Icons.add),
            );
          }),
        ));
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM