SfCalendar添加新预订后不更新,setState无效问题排查
问题:添加新预订后SfCalendar无法实时刷新,切换页面后才显示
我尝试在添加新预订时更新/刷新SfCalendar组件,已使用setState()但仍无效,新添加的预订仅在切换到AboutFragment再切回CalendarFragment时才显示。请问我哪里出错了?
相关代码:home.dart
import 'package:flutter/material.dart'; import 'package:syncfusion_flutter_calendar/calendar.dart'; import '../booking.dart'; import '../pages/login.dart'; List<Booking> bookingList = <Booking>[]; class HomePage extends StatefulWidget { const HomePage({super.key}); @override State<HomePage> createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { int _selectedFragment = 0; BookingDataSource _bookingDataSource = BookingDataSource(bookingList); void addNewBooking() { setState(() { Future<DateTime?> bookingDateTime = showBookingPicker(context: context); bookingDateTime.then((DateTime? value) { if (value != null) { bookingList.add(Booking('Reservation', value, value.add(const Duration(minutes: 30)), 'M')); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Booking Added')) ); _bookingDataSource = BookingDataSource(bookingList); } }); }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('STS'), centerTitle: true, automaticallyImplyLeading: false, actions: [ MenuAnchor( builder: (BuildContext context, MenuController menuController, Widget? child) { return IconButton( onPressed: () { if (menuController.isOpen) { menuController.close(); } else { menuController.open(); } }, icon: const Icon(Icons.more_vert), ); }, menuChildren: [ MenuItemButton( onPressed: () { Navigator.of(context).push( MaterialPageRoute( builder: (context) => const LoginPage(title: 'Log In'), ), ); }, child: const Padding( padding: EdgeInsets.all(4.0), child: Row( children: [ Icon(Icons.logout), SizedBox(width: 4.0), Text('Log Out'), ], ), ), ), ], ), ], ), body: _selectedFragment == 0 ? CalendarFragment(bookingDataSource: _bookingDataSource) : const AboutFragment(), floatingActionButton: FloatingActionButton( elevation: 0.0, tooltip: 'Add booking', onPressed: () { addNewBooking(); }, child: const Icon(Icons.add), ), bottomNavigationBar: NavigationBar( selectedIndex: _selectedFragment, onDestinationSelected: (int index) { setState(() { _selectedFragment = index; }); }, destinations: const [ NavigationDestination( icon: Icon(Icons.calendar_today), label: 'My Booking', ), NavigationDestination( icon: Icon(Icons.info), label: 'About Us', ), ], ), ); } } class CalendarFragment extends StatefulWidget { final BookingDataSource bookingDataSource; const CalendarFragment({Key? key, required this.bookingDataSource}) : super(key: key); @override State<StatefulWidget> createState() => _CalendarFragmentState(); } class _CalendarFragmentState extends State<CalendarFragment>{ @override Widget build(BuildContext context) { return SfCalendar( view: CalendarView.month, headerStyle: CalendarHeaderStyle( textStyle: Theme.of(context).textTheme.labelLarge, ), dataSource: widget.bookingDataSource, initialSelectedDate: DateTime.now(), monthViewSettings: const MonthViewSettings(showAgenda: true), ); } } class AboutFragment extends StatelessWidget { ... }
问题分析与解决
核心问题
你把setState()包裹在了showBookingPicker()的调用外层,但showBookingPicker()是异步操作,它的回调会在setState()执行完成后才触发。这意味着回调里更新_bookingDataSource的操作不会触发HomePage的UI重建,CalendarFragment自然无法拿到新的数据源。
修复方案
将setState()移到Future的回调内部,确保更新数据源的操作能触发UI重建:
void addNewBooking() { showBookingPicker(context: context).then((DateTime? value) { if (value != null) { setState(() { bookingList.add(Booking('Reservation', value, value.add(const Duration(minutes: 30)), 'M')); _bookingDataSource = BookingDataSource(bookingList); }); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Booking Added')) ); } }); }
更优的实现方式
不需要每次都创建新的BookingDataSource实例,直接调用数据源的notifyListeners()方法通知日历组件刷新,这样更高效:
- 保持数据源初始化不变:
BookingDataSource _bookingDataSource = BookingDataSource(bookingList);
- 修改添加预订的逻辑:
void addNewBooking() { showBookingPicker(context: context).then((DateTime? value) { if (value != null) { setState(() { bookingList.add(Booking('Reservation', value, value.add(const Duration(minutes: 30)), 'M')); _bookingDataSource.notifyListeners(); // 通知数据源更新 }); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Booking Added')) ); } }); }
另外,建议把全局的bookingList移到_HomePageState的状态中,避免全局状态带来的潜在问题,让状态管理更封闭可控。
内容的提问来源于stack exchange,提问作者Hadif Hatta
相关产品推荐
相关产品推荐

