在 Flutter 中使用 MobX 时如何观察可观察对象中的列表?

问题描述 投票:0回答:1

我有一个无法在 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();
                }
              },
            ),
          ],
        );
      },
    );
  }
}
flutter dart mobx
1个回答
0
投票

它一点也不优雅,但它有效:在商店内创建一个单独的可观察章节列表(并注意在可观察副本中反映真实 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);
  }
}

其余部分保持不变并且有效!

我暂时不会接受我的答案,希望有人提出一个不那么笨拙的解决方案。

© www.soinside.com 2019 - 2024. All rights reserved.