修复用户端订单列表生命周期与刷新
This commit is contained in:
@@ -8,45 +8,66 @@ class RecordListPage extends StatefulWidget {
|
||||
const RecordListPage({
|
||||
required this.title,
|
||||
required this.eyebrow,
|
||||
required this.viewModel,
|
||||
required this.sourceKey,
|
||||
required this.loader,
|
||||
this.description,
|
||||
this.floatingActionButton,
|
||||
this.onRecordTap,
|
||||
this.embedded = false,
|
||||
this.refreshToken = 0,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final String title;
|
||||
final String eyebrow;
|
||||
final String? description;
|
||||
final RecordListViewModel viewModel;
|
||||
final String sourceKey;
|
||||
final RecordLoader loader;
|
||||
final Widget? floatingActionButton;
|
||||
final ValueChanged<ClientRecord>? onRecordTap;
|
||||
final bool embedded;
|
||||
final int refreshToken;
|
||||
|
||||
@override
|
||||
State<RecordListPage> createState() => _RecordListPageState();
|
||||
}
|
||||
|
||||
class _RecordListPageState extends State<RecordListPage> {
|
||||
class _RecordListPageState extends State<RecordListPage>
|
||||
with AutomaticKeepAliveClientMixin<RecordListPage> {
|
||||
late RecordListViewModel _viewModel;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
widget.viewModel.load();
|
||||
_viewModel = RecordListViewModel(widget.loader)..load();
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant RecordListPage oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (widget.sourceKey != oldWidget.sourceKey) {
|
||||
_viewModel.dispose();
|
||||
_viewModel = RecordListViewModel(widget.loader)..load();
|
||||
return;
|
||||
}
|
||||
if (widget.refreshToken != oldWidget.refreshToken) {
|
||||
_viewModel.load();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
widget.viewModel.dispose();
|
||||
_viewModel.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
super.build(context);
|
||||
final content = ListenableBuilder(
|
||||
listenable: widget.viewModel,
|
||||
listenable: _viewModel,
|
||||
builder: (context, _) {
|
||||
final state = widget.viewModel;
|
||||
final state = _viewModel;
|
||||
if (state.loading && state.records.isEmpty) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
@@ -123,4 +144,7 @@ class _RecordListPageState extends State<RecordListPage> {
|
||||
body: content,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool get wantKeepAlive => true;
|
||||
}
|
||||
|
||||
@@ -14,23 +14,46 @@ class RecordListViewModel extends ChangeNotifier {
|
||||
List<ClientRecord> _records = const [];
|
||||
Object? _error;
|
||||
bool _loading = false;
|
||||
bool _disposed = false;
|
||||
int _requestGeneration = 0;
|
||||
|
||||
List<ClientRecord> get records => List.unmodifiable(_records);
|
||||
Object? get error => _error;
|
||||
bool get loading => _loading;
|
||||
|
||||
Future<void> load() async {
|
||||
final generation = ++_requestGeneration;
|
||||
_loading = true;
|
||||
_error = null;
|
||||
notifyListeners();
|
||||
_notifyIfActive();
|
||||
try {
|
||||
_records = await _loader();
|
||||
final records = await _loader();
|
||||
if (!_isCurrent(generation)) return;
|
||||
_records = records;
|
||||
} catch (error) {
|
||||
if (!_isCurrent(generation)) return;
|
||||
// 会话失效由统一路由接管,不在列表中重复展示网络错误。
|
||||
if (error is! SessionExpiredException) _error = error;
|
||||
} finally {
|
||||
_loading = false;
|
||||
notifyListeners();
|
||||
if (_isCurrent(generation)) {
|
||||
_loading = false;
|
||||
_notifyIfActive();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 仅允许最后一次请求且组件仍存活时写入状态。
|
||||
bool _isCurrent(int generation) => !_disposed && generation == _requestGeneration;
|
||||
|
||||
/// 避免异步请求在页面销毁后继续通知监听器。
|
||||
void _notifyIfActive() {
|
||||
if (!_disposed) notifyListeners();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_disposed = true;
|
||||
_requestGeneration += 1;
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user