【问题标题】:Managing state in Flutter using Provider使用 Provider 在 Flutter 中管理状态
【发布时间】:2021-01-15 11:41:54
【问题描述】:

我正在尝试在计数器应用程序上实现 Provider 状态管理,以更好地了解 Provider 的功能。我针对两个不同的文本小部件添加了两个按钮。所以,现在每当我点击这两个小部件中的任何一个时,Text 小部件都会得到更新并给出相同的值。我希望两个小部件彼此独立。 我已经使用了 ScopedModel 并得到了想要的结果,但现在我想尝试使用 provider。

图片链接:https://i.stack.imgur.com/ma3tR.png

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("====Home Page Rebuilt====");
    return Scaffold(
      appBar: AppBar(
        title: Text("HomePage"),
      ),
      body: Container(
          child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        //crossAxisAlignment:CrossAxisAlignment.center,
        children: [
          Consumer<CounterModel>(
            builder: (context, value, child) {
              return CustomWidget(
                number: value.count.toString(),
              );
            },
          ),
          Consumer<CounterModel>(
            builder: (context, value, child) {
              return CustomWidget(
                number: value.count.toString(),
              );
            },
          ),
        ],
      )),
    );
  }
}

class CustomWidget extends StatelessWidget {
  final String number;

  const CustomWidget({Key key, this.number}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    print("====Number Page Rebuilt====");
    return ButtonBar(
      alignment: MainAxisAlignment.center,
      children: [
        Consumer<CounterModel>(
          builder: (context, value, child) {
            return Text(
              value.count.toString(),
              style: Theme.of(context).textTheme.headline3,
            );
          },
        ),
        FlatButton(
          color: Colors.blue,
          onPressed: () =>
              Provider.of<CounterModel>(context, listen: false).increment(),
          child: Text("Click"),
        ),
      ],
    );
  }
}


 

【问题讨论】:

    标签: flutter flutter-provider


    【解决方案1】:

    如果您希望它们彼此独立,那么您需要以某种方式区分它们。我有一点不同的风格来实现提供者,它还没有让我失望。这是一个完整的例子。

    你应该将你的实现调整为这样的:

    在 CounterProvider.dart 文件中定义扩展 ChangeNotifier 的提供程序类

    import 'package:flutter/material.dart';
    
    class CounterProvider extends ChangeNotifier {
      /// You can either set an initial value here or use a UserProvider object
      /// and call the setter to give it an initial value somewhere in your app, like in main.dart
    
      int _counter = 0; // This will set the initial value of the counter to 0
    
      int get counter => _counter;
    
      set counter(int newValue) {
        _counter = newValue;
    
        /// MAKE SURE YOU NOTIFY LISTENERS IN YOUR SETTER
        notifyListeners();
      }
    }
    
    

    像这样使用 Provider Widget 包装您的应用程序

    import 'package:flutter/material.dart';
    import 'package:provider/provider.dart';
    /// don't forget to import it here too
    import 'package:app/CounterProvider.dart';
    
    
    void main() {
      runApp(
        MaterialApp(
          initialRoute: '/root',
          routes: {
            '/root': (context) => MyApp(),
          },
          title: "Your App Title",
        ),
      );
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MultiProvider(
          providers: [
            /// Makes data available to everything below it in the Widget tree
            /// Basically the entire app.
            ChangeNotifierProvider<CounterProvider>.value(value: CounterProvider()),
          ],
          child: MaterialApp(
            home: HomeScreen(),
          ),
        );
      }
    }
    

    在应用程序的任何位置访问和更新数据

    import 'package:flutter/material.dart';
    import 'package:provider/provider.dart';
    /// MAKE SURE TO IMPORT THE CounterProvider.dart file
    import 'package:app/CounterProvider.dart';
    
    class HomeScreen extends StatefulWidget {
      @override
      _HomeScreenState createState() => _HomeScreenState();
    }
    
    class _HomeScreenState extends State<HomeScreen> {
      CounterProvider counterProvider;
    
      @override
      Widget build(BuildContext context) {
        /// LISTEN TO THE CHANGES / UPDATES IN THE PROVIDER
        counterProvider = Provider.of<CounterProvider>(context);
    
        return Scaffold(
          appBar: AppBar(
            title: Text("HomePage"),
          ),
          body: Container(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              //crossAxisAlignment:CrossAxisAlignment.center,
              children: [
                _showCounterButton(1),
                _showCounterButton(2),
              ],
            ),
          ),
        );
      }
    
      Widget _showCounterButton(int i) {
        return ButtonBar(
          alignment: MainAxisAlignment.center,
          children: [
            Text(
              i == 1
                  ? counterProvider.counter1.toString()
                  : counterProvider.counter2.toString(),
              style: Theme.of(context).textTheme.headline3,
            ),
            FlatButton(
              color: Colors.blue,
              onPressed: () {
                /// UPDATE DATA IN THE PROVIDER. BECAUSE YOU're USING THE SETTER HERE,
                /// THE LISTENERS WILL BE NOTIFIED AND UPDATE ACCORDINGLY
                /// you can do this in any other file anywhere in the Widget tree, as long as
                /// it it beneath the main.dart file where you defined the MultiProvider
                i == 1
                    ? counterProvider.counter1 += 1
                    : counterProvider.counter2 += 1;
                setState(() {});
              },
              child: Text("Click"),
            ),
          ],
        );
      }
    }
    

    如果你愿意,你可以稍微改变一下实现。如果您有多个计数器,用于多个小部件,则只需在 CounterProvider.dart 文件中创建更多变量,并为每个计数器使用单独的 setter 和 getter。然后,要正确显示/更新它们,只需在 _showCounterButton() 方法和 onPressed: (){ switch case here, before setState((){}); } 内使用 switch case。

    希望这对您有所帮助,并让您更好地了解 Provider 的工作原理。

    【讨论】:

    • 我已经尝试过您的代码,但再次得到相同的结果。我会尝试在某处更改实现。
    • 很抱歉,我已经在演示应用程序中测试了我的代码,并且按钮可以单独工作。确保你从中得到了一切,而不仅仅是挑选的东西,因为你可能会遗漏一些重要的细节
    猜你喜欢
    • 1970-01-01
    • 2021-08-27
    • 2021-02-15
    • 2021-05-30
    • 2023-03-14
    • 2020-05-01
    • 2020-01-06
    • 1970-01-01
    • 2021-02-10
    相关资源
    最近更新 更多