Flutter消费者管理插件consumer的使用
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
更多关于Flutter消费者管理插件consumer的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
在Flutter中,Consumer
是 provider
包提供的一个非常重要的组件,它用于在函数式组件中访问和响应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
来监听和显示计数器的状态。
- 创建计数器模型:
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();
}
}
- 设置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(),
);
}
}
- 使用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'),
),
],
),
),
);
}
}
注意:在上面的代码中,Consumer
的 builder
函数接受三个参数:context
、value
(即Provider管理的对象实例,这里是 Counter
实例)和 child
。在 builder
函数内部,我们可以根据 value
的状态来构建UI。child
参数通常用于提供默认或静态内容,但在这个例子中,我们直接返回了动态内容。
此外,在 ElevatedButton
的 onPressed
回调中,我们使用了 Provider.of<Counter>(context, listen: false).increment()
来调用 increment
方法。这里设置 listen: false
是因为我们只想要调用方法,而不需要监听状态变化(因为点击按钮本身就会触发状态变化)。
这个示例展示了如何使用 Consumer
来监听和响应Provider状态的变化,从而更新UI。