簡體   English   中英

如何在不重建整個頁面的情況下使用 mobx 更改 ListTile 數據#Flutter

[英]How to change ListTile data with mobx without rebuilding the whole page #Flutter

我正在使用 mobx 學習 Flutter state 管理,並且我想在不重建整個頁面的情況下更改動態 listtile 的上下文,我嘗試了從 Mobx 商店獲取的可觀察列表,但我的示例在這里似乎不起作用。

此示例我想單擊名稱更改為單擊而不重建屏幕的項目,當我單擊時沒有任何反應,但是當我 go 返回另一個頁面並返回時,我發現動物的名稱已更改。

這是我的無狀態小部件

Class AnimalPageList extends StatelessWidget{
 
 @override
 Widget build(BuildContext context){    

var animalStore = context.watch<AnimalStore>();
var animals = animalStore.animalsList;

return Scaffold(
  appBar: AppBar(
    title: Text("Animals Page"),
  ),
  body: Center(
    child: Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
       Observer(builder: (_) =>
         ListView.builder(
           scrollDirection: Axis.vertical,
           shrinkWrap: true,
           itemCount: animals.length,
           itemBuilder: (BuildContext context, int index) {
             var pet = animalStore.getAnimal(index);
             //final petName = context.select((ObservableList<Animal> animals)=>animals[index].name);
             return ListTile(
                   key: ValueKey(pet.id),
                   enabled: true,
                   onTap: () async {
                     var rename = animals[index].name +" clicked";
                     animals[index].name = rename;
                   },
                   title: Observer(builder: (_) => Text(pet.name)),

             );
           },
         ),
       ),
      ],
    ),
  ),
);

這是我的 model 與商店

class Animal {
  final int id;

  @observable
  String name;

  Animal({this.id, this.name});

  factory Animal.fromJson(Map<dynamic, dynamic> json) {
    return new Animal(
      id: json['id'],
      name: json['name'],
    );
  }

  Map<dynamic, dynamic> toJson() {
    final Map<dynamic, dynamic> data = new Map<dynamic, dynamic>();
    data['id'] = this.id;
    data['name'] = this.name;
    return data;
  }
}

class AnimalStore = _AnimalStore with _$AnimalStore;

abstract class _AnimalStore with Store{


  @observable
  ObservableList animalsList = ObservableList<Animal>.of(
    [
      Animal(id: 1, name: 'cat'),
      Animal(id: 2, name: 'dog'),
      Animal(id: 3, name: 'mouse'),
      Animal(id: 4, name: 'horse'),
      Animal(id: 5, name: 'frog'),
    ]
  );

  @action
  getAnimal(int i){
    return animalsList[i];
  }


}

我可以安排哪種方式,model,商店和sreenwidget,這樣如果我點擊一個按鈕,它會根據需要更改名稱,而無需重建整個屏幕。

從您的代碼看來,列表大小是 static 並且它不會隨着時間而改變,基於這個事實,您可以 go 獲得一個簡單的解決方案,如下所示:

首先,您正在觀察整個列表,以及其中的 Text 小部件,此處過度設計。

只需將 Observer 包裹在ListTile周圍,這樣只有特定的ListTile會在更新到其觀察到的 var 時重建。 使用UniqueKey()作為每個元素的鍵。

此外,您需要引用 Observer 中的vars存儲 您可以在任何地方調用存儲操作,而無需在Observer小部件中。

您需要創建一個操作方法來更新動物的名稱。

提示:避免在循環或僅用於臨時保留的列表中創建新變量,構建器內的“變量重命名”不是一個好習慣。

通常我會創建一個代表商店的 object 的全局實例,並且可以被項目中的任何小部件/文件重用。

AnimalStore animalStore = AnimalStore();

代碼應修改如下:

//_AnimalStore class

   @action
   setAnimalName(int i, string name){
     animalsList[i].name = name;
   }

//AnimalPageList class

 Class AnimalPageList extends StatelessWidget{
     
     @override
     Widget build(BuildContext context){    
    
    // you dont realy need them
    var animalStore = context.watch<AnimalStore>();
    var animals = animalStore.animalsList;
    
    return Scaffold(
      appBar: AppBar(
        title: Text("Animals Page"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
           ListView.builder(
               scrollDirection: Axis.vertical,
               shrinkWrap: true,
               itemCount: animalStore.animalsList.length,
               itemBuilder: (BuildContext context, int index) {
                 return Observer(builder: (_) => ListTile(
                       key: ValueKey(pet.id),
                       enabled: true,
                       onTap: () {
                        animalStore.setAnimalName(index, animalStore.getAnimal(index).name +" clicked");
                       },
                       title: Text(animalStore.getAnimal(index)),
    
                 ));
               },
             ),
          ],
        ),
      ),
    );

首先,我認為@fpatelm 已經以不同的方式告訴了我要說的一切。 只是以不同的方式添加幾乎相同的解釋,以使事情更清楚。

更改 ObservableList 中元素的值不會更新屏幕,除非 ObservableList 中的每個個體也是 Observable。 沒有 Observables 作為元素的 Observable 列表只會在改變其大小(ObservableList.length)時發生變化。

解決此問題的一種方法是在更改任何元素時重建 Observable 列表。

@action
void onEditElement(Animal obj){
    final elemIndex = animalsList.findElementIndex(obj);
    final aux = ObservableList<Animal>.of([]);
    aux.copyAll(animalsList);
    aux[elemIndex] = obj;
    a.nimalsList = aux;
}

其次,您正在 {} 中克隆存儲,這意味着您與存儲在不同的 scope 中,不完全確定這是否是一個問題,但在我看來。

嘗試創建自定義磁貼,接收存儲值並返回 ListTile:

CustomTile extends StatelessWidget{
    const CustomTile(Animal pet);
    Builder{
        return ListTile(key: UniqueKey(), title: pet.name, ...,);
    }
}

itemBuilder: (BuildContext context, int index) {
    return CustomTile(
         animalStore.getAnimal(index),
    );
}

如果不能解決問題,請嘗試添加密鑰:UniqueKey(); 而不是 pet.id。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM