从Bloc迁移到Riverpod:Widget构建时如何初始化状态?
解决方案
方法1:使用StateNotifierProvider.family传递初始数据(推荐)
直接把journalEntry作为参数传递给StateNotifier构造函数,在初始化时就设置好初始状态,彻底避免在Widget生命周期内修改状态的问题。
步骤1:修改StateNotifier
新增initialEntry参数,用于初始化状态:
class EditJournalEntryController extends StateNotifier<EditJournalEntryState> { final JournalService journalService; EditJournalEntryController({ required this.journalService, required JournalEntry initialEntry, }) : super(EditJournalEntryState( selectedJournalType: initialEntry.type, rating: initialEntry.rating, )); void setSelectedJournalType(JournalType journalType) { state = state.copyWith(selectedJournalType: journalType); } void setRating(int rating) { state = state.copyWith(rating: rating); } }
步骤2:修改Provider为family类型
让Provider接收JournalEntry作为参数:
final editJournalEntryController = StateNotifierProvider.family<EditJournalEntryController, EditJournalEntryState, JournalEntry>( (ref, initialEntry) { final journalService = ref.watch(journalServiceProvider); return EditJournalEntryController( journalService: journalService, initialEntry: initialEntry, ); }, );
步骤3:在Widget中使用
传入journalEntry并监听状态:
class EditJournal extends StatelessWidget { const EditJournal({ Key? key, required this.journalEntry, }) : super(key: key); final JournalEntry journalEntry; @override Widget build(BuildContext context) { return Consumer( builder: ((context, ref, child) { final state = ref.watch(editJournalEntryController(journalEntry)); // 直接从state中取数据渲染UI return Column( children: [ Text('当前评分:${state.rating}'), // 编辑输入框示例 TextInput( labelText: '评分', value: state.rating?.toString() ?? '', onChanged: (value) => ref.read(editJournalEntryController(journalEntry).notifier).setRating(int.parse(value)), ) ], ); }), ); } }
方法2:使用ref.listen监听journalEntry变化
如果journalEntry会动态更新(比如上层组件传递的参数变化),可以用ref.listenSelf监听Widget参数变化,同步更新StateNotifier状态:
class EditJournal extends StatelessWidget { const EditJournal({ Key? key, required this.journalEntry, }) : super(key: key); final JournalEntry journalEntry; @override Widget build(BuildContext context) { return Consumer( builder: ((context, ref, child) { // 监听当前Widget的journalEntry参数变化 ref.listenSelf((previousWidget, currentWidget) { if (previousWidget?.journalEntry != currentWidget.journalEntry) { final notifier = ref.read(editJournalEntryController.notifier); notifier.setSelectedJournalType(currentWidget.journalEntry.type); notifier.setRating(currentWidget.journalEntry.rating); } }); final state = ref.watch(editJournalEntryController); return Column( children: [ Text('当前日志类型:${state.selectedJournalType}'), // 编辑控件 ], ); }), ); } }
方法3:延迟状态修改(临时方案)
如果以上方法都不适用,可以用Future.microtask把状态修改延迟到Widget构建完成后执行,注意要加判断避免重复更新:
class EditJournal extends StatelessWidget { const EditJournal({ Key? key, required this.journalEntry, }) : super(key: key); final JournalEntry journalEntry; @override Widget build(BuildContext context) { return Consumer( builder: ((context, ref, child) { final state = ref.watch(editJournalEntryController); final notifier = ref.read(editJournalEntryController.notifier); Future.microtask(() { // 仅当状态与journalEntry不一致时更新 if (state.selectedJournalType != journalEntry.type || state.rating != journalEntry.rating) { notifier.setSelectedJournalType(journalEntry.type); notifier.setRating(journalEntry.rating); } }); return Column( children: [ // 渲染UI ], ); }), ); } }
内容的提问来源于stack exchange,提问作者nyphur
相关产品推荐
相关产品推荐

