Flutter 状态管理

使用provider管理简单的状态

加入依赖:

#数据共享组件 https://github.com/rrousselGit/provider/blob/master/resources/translations/zh-CN/README.md
provider: 6.0.1

首先创建一个简单的实体类:

class User{
  ///用户名
  String username;
  ///凭证
  String accessToken;

  User({required this.username, required this.accessToken});

}

ChangeNotifier

用于向监听器发送通知

在修改完相应的状态并且需要更新UI的时候,需要调用notifyListeners();这个方法。

创建实体类对应的Notifier:

class UserNotifier extends ChangeNotifier {
  User _user = User(username: '', accessToken: '');

  ///设置用户信息
  set user(User value) {
    _user = value;
    notifyListeners();
  }

  ///获取用户信息
  User get user => _user;

  ///退出登录
  void logout() {
    _user.username = '';
    _user.accessToken = '';
    notifyListeners();
  }
}

ChangeNotifierProvider

ChangeNotifierProvider组件可以向其子孙结点暴露ChangeNotifier的一个实例

需要放置在使用状态管理的最上层组件之上

通常放在MyApp上面,用于管理全局状态:

runApp(
    ChangeNotifierProvider(
      create: (BuildContext context) => UserNotifier(),
      child: const MyApp(),
    )
);

这里的UserNotifier只会被实例化一次

如果想提供更多的状态,可以使用MultiProvider:

void main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (context) => CartModel()),
        Provider(create: (context) => SomeOtherClass()),
      ],
      child: const MyApp(),
    ),
  );
}

Consumer

用于调用Notifier,在需要使用状态管理组件的外层包裹

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: const Text("登录"),
    ),
    body: Center(
      child: Consumer<UserNotifier>(builder: (BuildContext context, user, child) {
        return Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Consumer<UserNotifier>(builder: (BuildContext context, user, child) {
              return Text(user.user.username == '' ? '未登录' : user.user.username);
            }),
            const SizedBox(
              height: 10,
            ),
            ElevatedButton(
                onPressed: () {
                  user.logout();
                },
                child: const Text("注销"))
          ],
        );
      }),
    ),
  );
}

需要使用泛型指定要访问的模型类型:Consumer<UserNotifier>

第二个参数user就是UserNotifier的实例

第三个参数用于优化,如果Consumer下面有一个庞大的子树,不需要根据状态改变,就可以在child中创建一次,然后通过builder获取该child,放到相应的位置:

return Consumer<CartModel>(
  builder: (context, cart, child) => Stack(
    children: [
      // Use SomeExpensiveWidget here, without rebuilding every time.
      if (child != null) child,
      Text("Total price: ${cart.totalPrice}"),
    ],
  ),
  // Build the expensive widget here.
  child: const SomeExpensiveWidget(),
);

Provider.of

有的时候你不需要模型中的 数据 来改变 UI,但是你可能还是需要访问该数据。比如,ClearCart 按钮能够清空购物车的所有商品。它不需要显示购物车里的内容,只需要调用 clear() 方法。

我们可以使用 Provider.of,并且将 listen 设置为 false

Provider.of<CartModel>(context, listen: false).removeAll();

在 build 方法中使用上面的代码,当 notifyListeners 被调用的时候,并不会使 widget 被重构。

posted @ 2021-11-11 10:53  Bin_x  阅读(93)  评论(0编辑  收藏  举报