当前位置: 首页 > news >正文

flutter: 用riverpod分离view层和viewmodel层

一,安装

项目地址:

https://pub.dev/packages/flutter_riverpod

安装:

dependencies:flutter:sdk: fluttergo_router: ^17.2.3flutter_riverpod: ^3.2.1

二,代码:

main.dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:myrouter/router/router.dart';void main() {// 包裹ProviderScope,使整个APP可以使用RiverpodrunApp(const ProviderScope(child: MyApp(),),);
}class MyApp extends StatelessWidget {const MyApp({super.key});// This widget is the root of your application.@overrideWidget build(BuildContext context) {return MaterialApp.router(title: 'Flutter Demo',theme: ThemeData(colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),useMaterial3: true,),routerConfig: router,);}

router.dart

import 'package:myrouter/pages/home_page.dart';
import 'package:go_router/go_router.dart';
import 'package:myrouter/views/UserView.dart';final router = GoRouter(routes: [GoRoute(path: "/",builder: (context, state) => const HomePage(),),GoRoute(path: '/setting',builder: (context, state) {// ✨ 核心代码:从 state.uri.queryParameters 中提取参数final id = state.uri.queryParameters['id'] ?? 0;final name = state.uri.queryParameters['name'] ?? '';final idint = int.tryParse(id?.toString() ?? '') ?? 0;return UserView(id: idint,name: name,);},)
]);

UserModel.dart


class UserModel {final int id;final String name;UserModel({required this.id, required this.name});
}

home_page.dart

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';class HomePage extends StatefulWidget {const HomePage({super.key});@overrideState<HomePage> createState() => _HomePageState();
}class _HomePageState extends State<HomePage> {@overrideWidget build(BuildContext context) {String name = '苏轼';int id = 123;return Scaffold(appBar: AppBar(backgroundColor: Theme.of(context).colorScheme.inversePrimary,title: const Text('主页'),),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[const Text('主页',style: TextStyle(fontSize: 40),),// 点击跳转到设置页面ElevatedButton(onPressed: () => GoRouter.of(context).push('/setting?name=${name}&id=${id}'),style: ElevatedButton.styleFrom(foregroundColor: Theme.of(context).colorScheme.onSecondary,backgroundColor: Theme.of(context).colorScheme.secondary,),child: const Text('跳转到设置页面'),)],),),);}
}

UserViewModel.dart

import 'package:flutter_riverpod/flutter_riverpod.dart';import '../models/userModel.dart';// ViewModel: 负责业务逻辑
class UserViewModel extends Notifier<UserModel?> {@overrideUserModel? build() => null; // 初始状态为空// 更新用户信息void setUser(int id, String name) {state = UserModel(id: id, name: name);}// 模拟修改用户信息的方法void updateUserInfo(int newId, String newName) {state = UserModel(id: newId, name: newName);}
}// 全局 Provider:让 View 可以访问这个 ViewModel
final userProvider = NotifierProvider<UserViewModel, UserModel?>(() {return UserViewModel();
});

UserView.dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';import '../viewmodels/UserViewModel.dart';class UserView extends ConsumerStatefulWidget {final int id;final String name;const UserView({super.key, required this.id, required this.name});@overrideConsumerState<UserView> createState() => _DetailPageState();
}class _DetailPageState extends ConsumerState<UserView> {@overridevoid initState() {super.initState();// 💡 关键点:进入页面时,将路由参数存入 ViewModelFuture.microtask(() {ref.read(userProvider.notifier).setUser(widget.id, widget.name);});}@overrideWidget build(BuildContext context) {// 监听 ViewModel 中的数据变化final user = ref.watch(userProvider);return Scaffold(appBar: AppBar(title: const Text('详情页')),body: Center(child: user == null? const CircularProgressIndicator(): Column(mainAxisAlignment: MainAxisAlignment.center,children: [Text('ID: ${user.id}', style: const TextStyle(fontSize: 24)),Text('姓名: ${user.name}', style: const TextStyle(fontSize: 24)),const SizedBox(height: 20),ElevatedButton(onPressed: () {// ✨ 核心:调用 ViewModel 的方法修改数据ref.read(userProvider.notifier).updateUserInfo(101, "杨万里");},child: const Text('更新为杨万里'),),],),),);}
}

三,测试效果:

image

image

 

http://www.jsqmd.com/news/758999/

相关文章:

  • Windows Cleaner深度体验:从C盘爆红到系统重生的真实转变
  • 长期项目中使用Taotoken用量预警功能管理资源消耗
  • R 4.5回测系统崩溃频发?深度解析timeBased、TTR与quantstrat v0.17.6兼容性黑洞(生产环境避坑手册)
  • 3分钟掌握YetAnotherKeyDisplayer:让键盘操作从隐形到可见的魔法工具
  • StyLua开发者指南:扩展格式化规则与自定义配置实现
  • OpenVoice性能优化指南:如何提升语音克隆质量和生成速度
  • task4
  • FreeRTOS消息队列实战:从xQueueCreate到xQueueReceive,手把手教你实现任务间通信
  • 网盘直链下载助手完整指南:如何在5分钟内掌握浏览器下载网盘文件的终极技术
  • 在 DXGI . 引入了新的功能,支持获得交换链发出开始渲染新帧的适当时机信号,通过等待此信号,可以降低输入的渲染延迟 ...
  • Dify私有化落地避坑清单:3大国产OS兼容性问题、5类中间件报错日志解析与7步快速回滚方案
  • Windows Defender移除工具深度解析:如何彻底释放系统性能潜力
  • Nintendo Switch大气层系统完整指南:从零开始掌握自定义固件
  • 如何快速上手ISD:5分钟学会交互式systemd单元管理
  • OpenVoiceV2核心技术原理揭秘:从音频处理到AI模型实现
  • 新闻媒体的多语言传播:hf_mirrors/ai-gitcode/seamless-m4t-v2-large的实时字幕生成技术
  • axios-retry源码解析:深入理解拦截器与重试机制实现原理
  • Markdown语法转换
  • 利用 Taotoken 多模型聚合能力为 AIGC 应用构建弹性后备方案
  • js 双击页面 开始/暂停 页面滚动
  • 深入DeepSeek-V3.1架构:671B参数MoE模型的技术突破
  • SCOPE框架:LLM智能体动态提示优化技术解析
  • AvalonEdit 5分钟快速上手:从零开始创建你的第一个文本编辑器
  • 【AI编程实战】你的 Claude Code 还是「单线程」?是时候学会「分心」了
  • 类的三大特性:继承、封装、多态
  • PipesHub AI自定义开发:如何扩展新的数据连接器和AI工具
  • API返回500却无日志?Dify调试暗箱操作大起底,7个隐藏诊断开关一键启用
  • 5个理由告诉你为什么WSABuilds是Windows上运行Android应用的最佳选择
  • 企业如何借助多模型聚合平台优化AI应用成本与选型
  • Sprintpilot:基于BMad Method的自动化开发与多智能体协作实践