我有一个无法在 Flutter 中工作的简化情况:MobX 可观察对象(Book)有一个我也想观察的章节列表,因此我的 UI 被重新绘制以显示刚刚创建的新章节。
实际上我有更复杂的模型,这只是我设法展示我的问题的最简单的案例。
当我创建新章节时,新章节不会显示在列表中,但如果我返回主页并返回,它会出现在章节列表中。
由于我的应用程序中的其他原因,我无法将 Book 中的 chapters 属性更改为 ObservableList:
final ObservableList<Chapter> chapters;
是禁忌。
我在 stackoverflow 中查看了几个类似的问题,但在其中任何一个上都找不到解决我的问题的方法。
如何观察当前书中的章节,以便我的 UI 在创建新章节后正确更新?
我的型号:
class Book {
final String title;
final List<Chapter> chapters;
Book(this.title, this.chapters);
}
class Chapter {
final String title;
Chapter(this.title);
}
我的 MobX 商店:
import 'book.dart';
import 'package:mobx/mobx.dart';
part 'book_editor_store.g.dart';
class BookEditorStore = BookEditorStoreBase with _$BookEditorStore;
abstract class BookEditorStoreBase with Store {
@readonly
Book _currentBook = Book('', []);
@readonly
Chapter? _currentChapter;
@computed
int get chapterCount => _currentBook?.chapters.length ?? 0;
@computed
List<Chapter> get chapters => _currentBook?.chapters ?? [];
@action
setBook(Book book) {
_currentBook = book;
}
@action
addChapter(Chapter chapter) {
_currentBook?.chapters.add(chapter);
}
}
我的main.dart:
import 'book_editor_page.dart';
import 'book_editor_store.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return Provider(
create: (context) => BookEditorStore(),
child: MaterialApp(
title: 'MobX reactions',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MainPage(),
),
);
}
}
class MainPage extends StatelessWidget {
const MainPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: const Text('Main Page'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => const BookEditorPage()),
);
},
child: const Text('Editor'),
),
),
);
}
}
我的图书编辑器页面:
import 'book_editor_store.dart';
import 'book.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class BookEditorPage extends StatelessWidget {
const BookEditorPage({super.key});
@override
Widget build(BuildContext context) {
final bookEditorStore = Provider.of<BookEditorStore>(context);
return Scaffold(
appBar: AppBar(
title: const Text('Book Editor'),
),
body: Column(
children: [
Observer(
builder: (_) => ListView.builder(
shrinkWrap: true,
itemCount: bookEditorStore.chapterCount,
itemBuilder: (_, index) {
final chapter = bookEditorStore.chapters[index];
return ListTile(
title: Text(chapter.title),
);
},
),
),
ElevatedButton(
onPressed: () => addChapter(context, bookEditorStore),
child: const Text('Add Chapter'),
),
],
),
);
}
void addChapter(BuildContext context, BookEditorStore bookEditorStore) {
final TextEditingController titleController = TextEditingController();
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('New Chapter'),
content: TextFormField(
controller: titleController,
decoration: const InputDecoration(hintText: 'Enter chapter title'),
autofocus: true,
),
actions: <Widget>[
TextButton(
child: const Text('Cancel'),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: const Text('Create'),
onPressed: () {
final String title = titleController.text;
if (title.isNotEmpty) {
bookEditorStore.addChapter(Chapter(title));
Navigator.of(context).pop();
}
},
),
],
);
},
);
}
}
它一点也不优雅,但它有效:在商店内创建一个单独的可观察章节列表(并注意在可观察副本中反映真实 Book.chapters 列表中的任何更改)。
只需将 BookEditorStore 更改为:
import 'book.dart';
import 'package:mobx/mobx.dart';
part 'book_editor_store.g.dart';
class BookEditorStore = BookEditorStoreBase with _$BookEditorStore;
abstract class BookEditorStoreBase with Store {
@readonly
Book _currentBook = Book('', []);
@readonly
Chapter? _currentChapter;
@computed
int get chapterCount => _chapters.length;
@readonly
ObservableList<Chapter> _chapters = ObservableList<Chapter>();
@action
setBook(Book book) {
_currentBook = book;
_chapters = ObservableList<Chapter>.of(book.chapters);
}
@action
addChapter(Chapter chapter) {
_currentBook.chapters.add(chapter);
_chapters.add(chapter);
}
}
其余部分保持不变并且有效!
我暂时不会接受我的答案,希望有人提出一个不那么笨拙的解决方案。