分为四个步骤
今天又对这个状态管理有了新的认识,上一文中我是不懂,这次感觉也挺爽的,和vue差不多了。。。。。
1、引入provider库
provider: ^6.0.2
2、创建需要共享的数据类
还是要继承ChangeNotifier类
//1、创建共享数据
class counterStore extends ChangeNotifier {
int _count = 100;
int get count => _count;
set count(int value) {
_count = value;
//通知监听者,也就是通知那个组件使用了该属性
notifyListeners();
}
}
3、直接使用ChangeNotifierProvider包裹住根组件
void main() {
//将provider放在顶层
runApp(ChangeNotifierProvider(
create: (ctx) => counterStore(),
child: MyAPP(),
));
}
ctx为上下文。。。。。
4、第一种:Provider.of
这种方法使用Provider.of<counterStore>(context).属性直接拿到数据。
Widget build(BuildContext context) {
int count = Provider.of<counterStore>(context).count;
return Container(
padding: EdgeInsets.fromLTRB(50, 0, 50, 0),
child: ListView(
children: [
ElevatedButton(
child: Text("$count"),
onPressed: () {
Navigator.pushNamed(context, "webSocketRoute");
},
),
]
)
)
}
其弊端就是,只要使用这种方式拿到数据,真个组件都会重新bulider,重新渲染
4、第二种:Consumer(相对推荐)
Consumer2<counterStore,useStore>可传递两个store
现在有这么个需求,通过点击让count++,那么代码就:
Consumer<counterStore>(
builder: (ctx, countVM, child) {
print(ctx);
return ElevatedButton(
child: Text("${countVM.count}"),
onPressed: () {
//通过countVM拿到数据,并修改
countVM.count++;
},
);
}),
builder有三个参数
ctx,表示Consumer组件上下文,
countVM,表示要数据共享的store,例如:counterStore
child:用来存放一个静态的组件
使用这个Consumer,可以让静态组件进行重新渲染。。
例子如下:
咱们把Text("${countVM.count}")组件弄成一个静态的:
Text("静态数据")
Consumer<counterStore>(
builder: (ctx, countVM, child) {
return ElevatedButton(
child: child,
onPressed: () {
//通过countVM拿到数据,并修改
countVM.count++;
},
);
},
child: Text("静态数据"),
),
Consumer的两个参数就出来了,child存放一个组件,而builder里面的child用来接收这个组件,
那么这个静态的组件就不会重新被渲染,大大降低了渲染消耗。。
优点只有使用Consumer包裹的组件才会重新执行其内置的builder,并且使用child能防止静态资源重新渲染。
4、第三种:selector(推荐)
Selector<counterStore, counterStore>(
selector: (ctx, countMV) => countMV,
shouldRebuild: (prev, next) => false,
builder: (ctx, countVM, child) {
print("object");
return ElevatedButton(
child: Text("${countVM.count}"),
onPressed: () {
//通过countVM拿到数据,并修改
countVM.count++;
},
);
},
child: Text("静态数据"),
),
代码有四个参数bulider、child和Consumer的参数是一样的不再介绍。。。。
Selector<counterStore, counterStore>(
selector: (ctx, countMV) => countMV,
shouldRebuild: (prev, next) => false,
builder: (ctx, countVM, child) {
},
child:"",
),
Selector<counterStore, changeStore>
第一个参数表示咱们定义的共享数据,第二个表示将第一个进行变化的数据
shouldRebuild: (prev, next) =>false||true
如果为flase,页面不渲染,否则为渲染。。
5、多个store时
将其封抽离出来
import 'package:provider/provider.dart';
import 'package:provider/single_child_widget.dart';
import 'counterStore.dart';
List<SingleChildWidget> providers = [
ChangeNotifierProvider(create: (ctx) => counterStore()),
ChangeNotifierProvider(create: (ctx) => counterStore()),
ChangeNotifierProvider(create: (ctx) => counterStore()),
ChangeNotifierProvider(create: (ctx) => counterStore()),
ChangeNotifierProvider(create: (ctx) => counterStore()),
ChangeNotifierProvider(create: (ctx) => counterStore()),
ChangeNotifierProvider(create: (ctx) => counterStore()),
];
在main中引入并使用
import 'store/storeList.dart';
void main() {
//将provider放在顶层
runApp(MultiProvider(
providers: providers,
child: MyAPP(),
));
}
6、总结对比
使用Provider.of会让其所在类重新渲染。
使用Consumer避免了整个类进行渲染,只渲染其包裹的组件,使用child创建静态组件,可避免重新渲染。
使用selector进行状态管理,除了拥有Consumer的功能外,还可改变使用的状态类,也可禁止其包裹的页面渲染,