📚 Flutter 状态管理系列文章目录
  1. Flutter 状态管理(setState、InheritedWidget、 Provider 、Riverpod、 BLoC / Cubit、 GetX 、MobX 、Redux)

  2. setState() 使用详解:原理及注意事项

  3. InheritedWidget 组件使用及原理

  4. Flutter 中 Provider 的使用、注意事项与原理解析(含代码实战)

  5. GetX 用法详细解析以及注意事项

  6. Flutter BLoC 使用详细解析

  7. Flutter MobX 响应式原理与实战详解

  8. Flutter Riverpod 使用详细解析

  9. Riverpod原理解析(实现一个自己的Riverpod

✨ 起点:为什么要了解 MobX?

作为一个刚开始接触 Flutter 状态管理的开发者,我最初接触到的是 setStateProvider 等方式。当我看到有人说 MobX 是“最像魔法的状态管理库”时,我开始好奇:为什么它能不写 setState 就自动刷新 UI?

带着这样的疑问,我开启了对 MobX 的深入探索。这篇文章就是我把所有探索过程系统整理后的总结,希望对你也有帮助。


🛠 一、MobX 的安装与基本使用

MobX 的核心有三大类:

概念说明
Observable可观察状态,类似变量。变化时自动触发 UI 更新
Action改变状态的行为,所有状态变更建议通过 action
Reaction监听变化后做副作用,比如打印日志、导航等

1. 添加依赖

pubspec.yaml 中:

dependencies:flutter:sdk: fluttermobx: ^2.2.0flutter_mobx: ^2.0.6dev_dependencies:build_runner: ^2.4.6mobx_codegen: ^2.4.0

2.创建一个 MobX Store(状态容器)

counter_store.dart

import 'package:mobx/mobx.dart';part 'counter_store.g.dart'; // 自动生成的文件class CounterStore = _CounterStore with _$CounterStore;abstract class _CounterStore with Store {int count = 0;void increment() {count++;}
}

生成代码命令:

flutter pub run build_runner build
# 或者自动监听:
flutter pub run build_runner watch

3. 使用 Observer 监听状态

import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'counter_store.dart';class CounterPage extends StatelessWidget {final CounterStore counter = CounterStore();Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("MobX Counter")),body: Center(child: Observer(builder: (_) => Text('${counter.count}',style: TextStyle(fontSize: 40),),),),floatingActionButton: FloatingActionButton(onPressed: counter.increment,child: Icon(Icons.add),),);}
}

📚 二、MobX 核心注解说明

注解作用示例
@observable可监听变量@observable int count = 0;
@action状态改变函数@action void increment() => count++;
@computed派生状态String get fullName => "$firstName $lastName";

🧩 三、不同类型的 Observer 使用方式

类型使用场景是否支持 child是否自动跟踪依赖
Observer通用 UI 刷新
Observer.builder自定义构建器
ObserverWidget(自定义)可封装为组件
Observer + child:子组件不依赖状态,可优化性能

1️⃣ 最常用的 Observer

适用于所有直接在 build() 方法中监听 observable 状态的场景。

✅ 示例:
Observer(builder: (_) => Text('${counter.count}',style: TextStyle(fontSize: 32),),
)

每当 counter.count 更新时,Text 会自动重建。


2️⃣ Observer + child 优化重建

用于优化性能:当 UI 中部分元素是静态的,可以通过 child 参数避免重建。

✅ 示例:
Observer(child: Icon(Icons.favorite), // 不会因为状态变化而重建builder: (_, child) => Row(mainAxisAlignment: MainAxisAlignment.center,children: [child!,SizedBox(width: 8),Text('${counter.count}'),],),
)

Icon 是静态内容,MobX 不会重复创建,节省性能。


3️⃣ 封装成组件:自定义 ObserverWidget

当你想将 Observer 封装成复用组件时,可创建一个继承自 StatelessWidgetObserver 控件。

✅ 示例:
class CountText extends StatelessWidget {final CounterStore store;const CountText({required this.store});Widget build(BuildContext context) {return Observer(builder: (_) => Text('${store.count}', style: TextStyle(fontSize: 24)),);}
}

使用方式:

CountText(store: counterStore)

4️⃣ ListView/GridView 中的 Observer

当你需要对列表内容做响应式刷新时,每个 item 可以使用 Observer 包裹。

✅ 示例:
Observer(builder: (_) => ListView.builder(itemCount: todoStore.todos.length,itemBuilder: (_, index) {final todo = todoStore.todos[index];return Observer(builder: (_) => CheckboxListTile(value: todo.done,onChanged: (_) => todo.toggleDone(),title: Text(todo.title),),);},),
)

每个 CheckboxListTile 都会监听自己对应的 todo.done,提高效率。


🧠 补充:多层 Observer 嵌套性能说明

MobX 的响应式追踪是“精确依赖感知”的,每个 Observer 只监听自己用到的 @observable不会因为 store 中其他字段变化而重建,比传统 Provider 更细粒度。


✅ 小结对比
类型优势适用场景
Observer最常用,自动追踪通用响应式 UI
Observer + child性能优化静态元素嵌入 UI
自定义 StatelessWidget 包裹 Observer组件复用通用响应式组件
列表中嵌套 Observer精细追踪每一项变化todo、商品列表

✅ MobX 为什么可以“这么做”——原理解析

一、核心机制:可观察(Observable) + 自动追踪(Tracking)
  1. @observable 的变量不是普通变量,而是被 MobX 包装成了 可追踪对象(Atom)

  2. Observer 被构建时,MobX 开启一个 “追踪上下文”(Tracking Context):

    • Observer.builder() 中访问了哪些 @observable,就自动把这些变量注册为“依赖”。
  3. 一旦这些依赖发生变化,MobX 会自动通知 Observer 重新构建 UI。


二、过程举例说明

int count = 0;Observer(builder: (_) => Text('$count'),
)

➡ MobX 做了什么?

  1. 初次 build 时读取了 count,MobX 会记录下这个“读取动作”:

    “这个 Observer 正在依赖 count!”

  2. 后续调用 count++(即修改 observable)时:

    • MobX 发现 count 改了,它就通知所有依赖 count 的观察者(也就是这个 Observer)重新执行 builder,从而刷新 UI。

三、MobX 响应式模型的类比

可以把 MobX 的响应式系统类比成:

  • @observable = 数据源(比如“温度传感器”)
  • Observer = 显示模块(比如“电子温度计”)
  • MobX = 自动布线系统,知道哪个显示器监听哪个传感器

只要传感器变化,显示模块就刷新。开发者什么都不用手动做。


四、底层依赖追踪的原理:Atom + Reaction

MobX 的核心类是:

说明
Atom每个 observable 变量都是一个 Atom
Reaction每个 Observer 内部注册了一个 reaction
Context每次执行 builder() 时,MobX 开启上下文收集依赖
Derivation指的是任何依赖 observable 的函数,比如 computedObserver

五、Flutter 中 UI 为什么可以重建?

因为 Observer 继承自 StatelessWidget,而其内部逻辑其实是这样的(伪代码):

class Observer extends StatelessWidget {final Reaction _reaction;Observer({required WidgetBuilder builder}) {_reaction = Reaction(() {// 当依赖的 observable 改变时,调用 setState 或 rebuild});}Widget build(BuildContext context) {// 启动依赖收集_reaction.track(() {builder(context); // 在这个过程中读取 observable,就会注册依赖});}
}

✅ 总结一句话

MobX 可以“这么做”,是因为它在 Observer.builder 执行时自动收集依赖变量,一旦这些变量变化,MobX 会主动通知刷新 UI。你不需要写 setState,它已经帮你自动“追踪 + 通知 + 重建”了。


⚙️ 五、自己手写一个简化版 MobX(低配实现)

太棒了!下面我就来写一个低配版的 MobX 响应式系统实现,让你直观理解它的底层机制。这个版本包括:

  1. Observable<T>:可观察变量
  2. Reaction:监听依赖并自动响应
  3. autorun():一个简化版的 Observer 行为
  4. 自动依赖追踪:MobX 的“神操作”

🧠 目标:当你读取 observable 的时候自动注册依赖,当你修改 observable 的时候,能触发依赖函数。


🔧 第一步:实现全局上下文收集机制

typedef VoidCallback = void Function();class ReactiveContext {static final ReactiveContext _instance = ReactiveContext._internal();VoidCallback? _currentReaction;factory ReactiveContext() => _instance;ReactiveContext._internal();void setCurrentReaction(VoidCallback? reaction) {_currentReaction = reaction;}VoidCallback? get currentReaction => _currentReaction;
}

🔮 第二步:实现 Observable

class Observable<T> {T _value;final Set<VoidCallback> _listeners = {};Observable(this._value);T get value {// 自动依赖收集final reaction = ReactiveContext()._currentReaction;if (reaction != null) {_listeners.add(reaction);}return _value;}set value(T newValue) {if (newValue != _value) {_value = newValue;// 通知所有监听者for (var listener in _listeners) {listener();}}}
}

🔁 第三步:实现 autorun(模拟 Observer)

void autorun(VoidCallback runner) {void wrapped() {ReactiveContext().setCurrentReaction(wrapped); // 注册当前 reactionrunner();ReactiveContext().setCurrentReaction(null); // 清理}wrapped(); // 初始执行一次,收集依赖
}

🎯 示例:模拟 Counter 自动追踪 + 响应

void main() {final count = Observable(0);autorun(() {print("当前 count 是:${count.value}");});// 模拟用户操作count.value = 1; // 自动触发 autorun 输出count.value = 2;
}
✅ 输出:
当前 count 是:0
当前 count 是:1
当前 count 是:2

🧠 总结:

MobX 组件我们实现的类
@observableObservable<T>
Observerautorun()
依赖追踪ReactiveContext
reactionVoidCallback 注册

💡 提升建议:

你可以进一步加上:

  • computed(派生值)
  • action(封装状态更新)
  • dispose()(清除监听)
  • 与 Flutter Widget 结合(如用 ValueListenableBuilder 或自写 ObserverWidget

🗺 六、MobX 响应流程图

Observable↓ (读取)
Reaction ← 自动注册依赖↓
值变化?↓ 是
刷新 UI(Observer)

(你也可以参考文中附图,完整展现了 MobX 的响应链条)


✅ 七、总结:MobX 值得用吗?

MobX 让状态管理变得优雅和现代化:

  • 不用写 setState
  • 不需要 notifyListeners
  • 自动依赖收集
  • 最细粒度响应更新

适合追求响应式编程和简洁架构的开发者。如果你喜欢 Vue、Svelte 那种“写了就动”的感觉,MobX 会让你爱不释手。


🧰 附加建议

  • 推荐将每个 Store 模块化、组件化;
  • 可结合依赖注入工具如 GetIt 使用;
  • 想要更复杂管理?可引入 reactionwhen 进行副作用管理。
📚 Flutter 状态管理系列文章目录
  1. Flutter 状态管理(setState、InheritedWidget、 Provider 、Riverpod、 BLoC / Cubit、 GetX 、MobX 、Redux)

  2. setState() 使用详解:原理及注意事项

  3. InheritedWidget 组件使用及原理

  4. Flutter 中 Provider 的使用、注意事项与原理解析(含代码实战)

  5. GetX 用法详细解析以及注意事项

  6. Flutter BLoC 使用详细解析

  7. Flutter MobX 响应式原理与实战详解

  8. Flutter Riverpod 使用详细解析

  9. Riverpod原理解析(实现一个自己的Riverpod

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/86848.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/86848.shtml
英文地址,请注明出处:http://en.pswp.cn/web/86848.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

浅谈国产数据库多租户方案:提升云计算与SaaS的资源管理效率

近年来&#xff0c;“数据库多租户”这一概念在技术圈内频频出现&#xff0c;成为云计算和SaaS&#xff08;软件即服务&#xff09;架构中的重要组成部分。多租户架构不仅为企业提供了高效的资源隔离与共享解决方案&#xff0c;还能大幅降低成本&#xff0c;提高系统的可扩展性…

Wpf的Binding

前言 wpf的Binding就像一个桥梁&#xff0c;它的作用就是连接逻辑层与界面层&#xff0c;既能够把逻辑层的数据搬到界面层展示&#xff0c;又能将界面层的数据更改后传递到逻辑层&#xff0c;Binding的数据来源就是Binding的源&#xff0c;数据展示的地方就是Binding的目标。 …

嵌入式单片机中SPI串行外设接口控制与详解

串行外设接口(Serial Peripheral Interface)的简称也叫做SPI,是一种高速的、全双工同步通信的一种接口,串行外设接口一般是需要4根线来进行通信(NSS、MISO、MOSI、SCK),但是如果打算实现单向通信(最少3根线),就可以利用这种机制实现一对多或者一对一的通信。 第一:…

【世纪龙科技】新能源汽车动力电池总成装调与检修教学软件

在新能源汽车产业“技术迭代快、安全要求高、实操风险大”的背景下&#xff0c;职业院校如何以“项目式教学改革”为突破口&#xff0c;破解传统实训“高成本、高风险、低效率”的困局&#xff1f;江苏世纪龙科技以桌面VR沉浸式技术为支点&#xff0c;推出《新能源动力电池总成…

GO泛型编程面试题及参考答案

目录 什么是 Go 中的泛型?Go 从哪个版本开始支持泛型? 在 Go 中如何定义一个带类型参数的函数? 如何为结构体添加类型参数? 使用 any 关键字和自定义类型约束有什么区别? 泛型中~T 的语义及其实际应用是什么? 如何在函数中使用多个类型参数?举例说明。 Go 泛型支…

ReactRouter-404路由配置以及两种路由模式

404路由 场景&#xff1a;当浏览器输入url的路径在整个路由配置中都找不到对应的path&#xff0c;为了用户体验&#xff0c;可以使用404兜底组件进行渲染 实现步骤 准备一个404组件在路由表数组的末尾&#xff0c;以*号作为路由path配置路由 新建404组件 const NotFound (…

《Kubernetes》Service 详解+Ingress

主要介绍kubernetes的流量负载组件&#xff1a;Service和Ingress。 1. Service 1.1 Service介绍 在kubernetes中&#xff0c;pod是应用程序的载体&#xff0c;我们可以通过pod的ip来访问应用程序&#xff0c;但是pod的ip地址不是固定的&#xff0c;这也就意味着不方便直接采用…

常见网络知识,宽带、路由器

常见网络知识&#xff0c;宽带、路由器 1、关于光猫、桥接和路由接法 现在的光猫都带有路由功能&#xff0c;即光猫、路由一体。不需要路由器也能让设备连上&#xff0c;但是一般来说路由功能穿墙有限&#xff0c;放在弱电箱/多媒体箱里的光猫发射出来的wifi信号其实是很难在…

Android应用缓存清理利器:WorkManager深度实践指南

本文将带你全面掌握使用WorkManager实现缓存清理的技术方案&#xff0c;从基础原理到性能优化&#xff0c;提供完整代码实现和工程实践指南 一、缓存清理的必要性与挑战 在Android应用开发中&#xff0c;缓存管理是优化应用性能的关键环节。随着应用使用时间增长&#xff0c;缓…

如何理解构件“可独立部署”的特性

构件的“可独立部署”特性是其区别于普通代码模块的核心特征之一&#xff0c;我们可以通过生活案例和技术原理解释来理解这一特性&#xff1a; 一、生活类比&#xff1a;从“家电维修”看独立部署 假设你家的空调坏了&#xff0c;维修时只需拆开空调外机更换压缩机&#xff0…

uni-app subPackages 分包加载:优化应用性能的利器

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》、《前端求职突破计划》 &#x1f35a; 蓝桥云课签约作者、…

CentOS 8 安装第二个jdk隔离环境

1.适用于原本已经装了jdk8&#xff0c;现在需要安装jdk17&#xff1a; 多版本 JDK 共存不希望修改系统默认 JavaDocker 或脚本化部署 2. 下载 Adoptium&#xff08;原 AdoptOpenJDK&#xff09; 的 OpenJDK 17&#xff1a; cd /指定目录 sudo wget https://github.com/adopti…

Day.43

getitem方法&#xff1a; class MyList: def __init__(self): self.data [10, 20, 30, 40, 50] def __getitem__(self, idx): return self.data[idx] my_list_obj MyList() print(my_list_obj[2]) len方法&#xff1a; class MyList: def __init__(self): self.data [10…

三七互娱GO面经及参考答案

MySQL 有哪些存储引擎?MyISAM 如何存储数字类型数据? MySQL 拥有多种存储引擎,每种都有其独特的特性和适用场景。常见的存储引擎包括 InnoDB、MyISAM、Memory、CSV、Archive、Federated 等。 InnoDB 是 MySQL 5.5 版本之后的默认存储引擎,它支持事务、外键、行级锁和崩溃恢…

git常见问题汇总-重复提交/删除已提交文件等问题

git常见问题汇总&#xff1a; 1&#xff0c;已经commit的文件需要修改 /删除&#xff0c;应该怎么处理&#xff1f; 2&#xff0c;自己建的分支“branch1”显示“rebasing branch1”&#xff0c;这是什么情况&#xff1f; 3&#xff0c;由于内容修改/优化&#xff0c;在同一个…

Python实例题:简单的 Web 服务器

目录 Python实例题 题目 要求&#xff1a; 解题思路&#xff1a; 代码实现&#xff1a; Python实例题 题目 简单的 Web 服务器 要求&#xff1a; 使用 Python 的 socket 模块实现一个简单的 HTTP 服务器。支持以下功能&#xff1a; 处理 GET 和 POST 请求静态文件服务…

3.Stable Diffusion WebUI本地部署和实践

本文看了(68 封私信) 逼真的图片生产 | Stable Diffusion WebUI本地部署看这一篇就够了 - 知乎和(68 封私信) Stable Diffusion WebUI 实践: 基本技法及微调 - 知乎&#xff0c;本人根据它们部署了一遍&#xff0c;中间遇到一些报错&#xff0c;但根据报错提示解决了问题&#…

阿里最新开源:Mnn3dAvatar 3D数字人框架, 无需联网,本地部署可离线运行,支持多模态实时交互

Mnn3dAvatar 3D数字人框架是基于阿里巴巴开源的轻量级深度学习推理框架MNN&#xff08;Mobile Neural Network&#xff09;开发的全新3D数字人框架。Aibot亲测这是一个可以在本地运行、完全离线、支持多模态实时交互的智能数字人App。可以在本地私有部署。感兴趣的同学可以拿来…

03【C++ 入门基础】函数重载

文章目录 引言函数重载函数重载的使用函数重载的原理extern “C” 静态多态 总结 引言 通过00【C 入门基础】前言得知&#xff0c;C是为了解决C语言在面对大型项目的局限而诞生&#xff1a; C语言面对的现实工程问题&#xff08;复杂性、可维护性、可扩展性、安全性&#xff0…

改写一个小项目: flask -------------------> next js

现在&#xff0c;请把上面改写代码的过程中&#xff0c;所有的过程&#xff0c;都写下来&#xff0c;写为文章的形式&#xff0c;内容比较长&#xff0c;你可以分多次输出。而且要求语言幽默&#xff0c;苦中作乐的心态。分条理&#xff0c;要清晰。一场从 Flask 到 Next.js 的…