Flutter消费者管理插件consumer的使用

发布于 1周前 作者 yuanlaile 来自 Flutter

Flutter消费者管理插件consumer的使用

安装consumer

pubspec.yaml文件中添加以下依赖项:

dependencies:
  consumer: ^2.3.0

示例代码

下面是一个完整的示例,展示了如何使用Flutter消费者管理插件consumer来管理状态。

import 'package:flutter/material.dart';
import '../lib/consumer.dart';

void main() => runApp(MyApp());

// 定义一个状态类
class ExampleState {
  int counter = 0;
}

// 创建一个消费者实例
var consumer = Consumer(ExampleState());

// Flutter基础示例,将StatefulWidget转换为 StatelessWidget
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  _incrementCounter() {
    consumer.setState((state) => state.counter++);
  }

  @override
  Widget build(BuildContext context) {
    print('only run once');

    return Scaffold(
      appBar: AppBar(
        title: Text("Hello Consumer"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              'You have pushed the button this many times:',
            ),
            consumer.build(
              // 使用memo订阅有效变化
              (ctx, state) {
                print('update when state.counter change');
                return Text(
                  '$state.counter',
                  style: Theme.of(context).textTheme.headline4,
                );
              },
              memo: (state) => [state.counter],
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

关于memo

memo参数借鉴了React Hooks的设计,可以显著提高性能。例如:

Column(
  children: [
    consumer.build((ctx, state) {
      print('Update when state.age change');
      return Text(
        state.age.toString(),
        style: Theme.of(ctx).textTheme.headline4,
      );
    },
    memo: (state) => [state.age],
  ],
);

如果只更新state.name,只有使用memo: (state) => [state.name]的子组件才会被重新渲染。

全例程示例

import 'package:consumer/consumer.dart';

class ExampleState {
  int counter = 0;
  String time = DateTime.now().toString();
}

var consumer = Consumer(ExampleState());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Material App',
      theme: ThemeData(primaryColor: Colors.blue),
      home: Scaffold(
        appBar: AppBar(
          title: Text("hello"),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text('counter:'),
              consumer.build(
                (ctx, state) {
                  print("update state.counter");
                  return Text(
                    state.counter.toString(),
                    style: Theme.of(ctx).textTheme.headline4,
                  );
                },
                memo: (state) => [state.counter],
              ),
              Container(
                child: TextButton(
                  onPressed: () {
                    consumer.setState((state) {
                      state.counter += 1;
                    });
                  },
                  child: Text("Only Change counter",
                    style: TextStyle(fontSize: 24)),
                ),
                margin: EdgeInsets.only(top: 20, bottom: 40),
              ),
              Text('time:'),
              consumer.build(
                (ctx, state) {
                  print("update state.time");
                  return Text(
                    state.time.toString(),
                    style: Theme.of(ctx).textTheme.headline4,
                  );
                },
                memo: (state) => [state.time],
              ),
              Container(
                child: TextButton(
                  onPressed: () {
                    consumer.setState((state) {
                      state.time = DateTime.now().toString();
                    });
                  },
                  child: Text("Only Change timee", style: TextStyle(fontSize: 24)),
                ),
                margin: EdgeInsets.only(top: 20),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

为什么不能在consumer.setState之前更新子界面?

  • 如果你使用state.name,可能memo不会订阅state.name
  • memo可能没有返回任何内容。
  • 只更新列表或映射,但不设置新的列表或映射时可能会出错。

状态技巧

如果你需要在更新之前改变数据,可以在状态类中添加函数属性。例如:

class ExampleState {
  int lastChangeNamesIndex;
  List<String> names = ['dog', 'cat'];

  changeNameAt(int index, String name) {
    lastChangeNamesIndex = index;
    List<String> nextNames = [...names];
    nextNames[index] = name;
    names = nextNames;
  }
}

var consumer = Consumer(ExampleState());

Center(
  child: consumer.build((ctx, state) {
    return Text(
      state.names[state.lastChangeNamesIndex],
      style: Theme.of(context).textTheme.display1,
    );
  },
  memo: (state) => [state.names, state.lastChangeNamesIndex],
),
);

// 更容易地更新名字和lastChangeNamesIndex
consumer.setState((state){
  state.changeNameAt(0, 'monkey');
})

更多关于Flutter消费者管理插件consumer的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter消费者管理插件consumer的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter中,Consumerprovider 包提供的一个非常重要的组件,它用于在函数式组件中访问和响应Provider的状态变化。相比于 Provider.of<T>(context)Consumer 提供了一种更简洁且高效的方式来监听Provider的状态,并在状态变化时自动重建UI。

下面是一个简单的示例,展示了如何在Flutter中使用 Consumer 来管理状态。

首先,确保你的 pubspec.yaml 文件中已经添加了 provider 依赖:

dependencies:
  flutter:
    sdk: flutter
  provider: ^x.y.z  # 替换为最新版本号

然后,运行 flutter pub get 来安装依赖。

接下来,让我们创建一个简单的计数器应用,使用 Consumer 来监听和显示计数器的状态。

  1. 创建计数器模型
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class Counter with ChangeNotifier {
  int _count = 0;

  int get count => _count;

  void increment() {
    _count++;
    notifyListeners();
  }
}
  1. 设置Provider

main.dart 中,我们使用 MultiProvider 来包装整个应用,并在其中定义 Counter 的Provider。

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'counter.dart'; // 假设计数器模型定义在这个文件中

void main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => Counter()),
      ],
      child: MyApp(),
    ),
  );
}

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

MyHomePage 中,我们使用 Consumer 来监听 Counter 的状态,并在UI中显示计数器值。

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

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Consumer Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Consumer<Counter>(
              builder: (context, counter, child) {
                return Text(
                  'You have pushed the button this many times:',
                  style: Theme.of(context).textTheme.headline4,
                );
              },
              child: Text(
                '${counter.count}',
                style: Theme.of(context).textTheme.headline4,
              ),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                Context context = context; // 这里只是为了演示,实际不需要这行
                Provider.of<Counter>(context, listen: false).increment();
              },
              child: Text('Increment'),
            ),
          ],
        ),
      ),
    );
  }
}

注意:在上面的代码中,Consumerbuilder 函数接受三个参数:contextvalue(即Provider管理的对象实例,这里是 Counter 实例)和 child。在 builder 函数内部,我们可以根据 value 的状态来构建UI。child 参数通常用于提供默认或静态内容,但在这个例子中,我们直接返回了动态内容。

此外,在 ElevatedButtononPressed 回调中,我们使用了 Provider.of<Counter>(context, listen: false).increment() 来调用 increment 方法。这里设置 listen: false 是因为我们只想要调用方法,而不需要监听状态变化(因为点击按钮本身就会触发状态变化)。

这个示例展示了如何使用 Consumer 来监听和响应Provider状态的变化,从而更新UI。

回到顶部