繁体   English   中英

Provider (ChangeNotifier) 小部件内的有状态小部件未更新

[英]Stateful widget inside an Provider (ChangeNotifier) widget does not get updated

我有一个 Stateless-Provider 小部件及其 ChangeNotifier 模型。 在 Provider 内部,有一个 Stateful 小部件。 调用 notifyListeners 时,无状态小部件中的所有小部件都会更新,有状态的小部件除外。 我在这里缺少什么,我该怎么做? 此处提供一个简化示例:按下按钮后,预期结果为First: The value is 1st ,但实际输出为First: The value is 2nd

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class Model extends ChangeNotifier {
  final List<ListElement> elements;
  Model({required this.elements});

  void add() {
    elements.insert(0, ListElement(name: "First", value: "1st"));
    notifyListeners();
  }
}


class ListElement {
  final String name;
  var value;
  ListElement({required this.name, required this.value});
}

class ValueWidget extends StatefulWidget {
  final String value;
  ValueWidget({required this.value});

  @override
  State<StatefulWidget> createState() => _ValueWidget(value: value);

}

class _ValueWidget extends State<ValueWidget> {

  String value;
  _ValueWidget({required this.value});

  @override
  Widget build(BuildContext context) {
    return Text("The value is ${value}.");
  }

}

class StatelessPage extends StatelessWidget {
  
  final model = Model(elements: [
    ListElement(name: "Second", value: "2nd"),
      ListElement(name: "Third", value: "3rd")]);
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ChangeNotifierProvider(
        create: (context) => model,
        child: ConsumerWidget())
    );
  }
}

class ConsumerWidget extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return Consumer<Model>(builder: (context, model, _) {
      return SingleChildScrollView(
        child: Container(
          padding: EdgeInsets.fromLTRB(10, 30, 10, 10000),
          child: Column(
            children: [Column(
                children: model.elements.map((element) {
                  return Row(children: [
                    Text("${element.name}: "),
                    ValueWidget(value: element.value)
                  ]);
                }).toList(),
            ),
              TextButton(onPressed: model.add,
                  child: Text("Add element to beginning")),
            ],
          ),
        ),
      );
    });
  }
}

请考虑这是我的生产代码的简化版本,将整个 Provider 类更改为有状态的类会很困难。

编辑:感谢 Aimen 显示路径。 最终起作用的是仅使用 Stateful wiget (ValueWidget) 中列表elements的索引。 并从模型中获取数据。 我认为这样做的原因是,如果独立的 Stateful-widget 不受影响,它就不会重建。 我们需要影响小部件的build部分。 粘贴更改后的工作代码。




import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class Model extends ChangeNotifier {
  final List<ListElement> elements;
  Model({required this.elements});

  void add() {
    elements.insert(0, ListElement(name: "First", value: "1st"));
    notifyListeners();
  }
}


class ListElement {
  final String name;
  var value;
  ListElement({required this.name, required this.value});
}

class ValueWidget extends StatefulWidget {
  final int ind;
  final Model model;
  ValueWidget({required this.ind, required this.model});

  @override
  State<StatefulWidget> createState() => _ValueWidget(
      ind: ind, model: model);
}

class _ValueWidget extends State<ValueWidget> {

  final int ind;
  final Model model;
  _ValueWidget({required this.ind, required this.model});

  @override
  Widget build(BuildContext context) {
    // Can also use Provider like this so that it does not need to be passed
    // final model = Provider.of<Model>(context, listen: true);
    // This is the part because of which widget is getting rebuilt
    final element = model.elements[ind];
    return Text("The value is ${element.value}.");
  }
}

class StatelessPage extends StatelessWidget {
  
  final model = Model(
      elements: [
    ListElement(name: "Second", value: "2nd"),
      ListElement(name: "Third", value: "3rd")]
  );
  
  @override
  Widget build(BuildContext context) {

    return Scaffold(
      body: ChangeNotifierProvider(
        create: (context) => model,
        child: ConsumerWidget())
    );
  }
}

class ConsumerWidget extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return Consumer<Model>(builder: (context, model, _) {
      return SingleChildScrollView(
        child: Container(
          padding: EdgeInsets.fromLTRB(10, 30, 10, 10000),
          child: Column(
            children: [Column(
                children:
                  model.elements.asMap().entries.map((ele) {
                  return Row(children: [
                    Text("${ele.value.name}: "),
                    ValueWidget(ind: ele.key, model: model),
                  ]);
                }).toList(),
            ),
              TextButton(onPressed: model.add,
                  child: Text("Add element to beginning")),
            ],
          ),
        ),
      );
    });
  }
}

你没有在有状态的小部件中实现提供者你只是通过一个参数传递一个值你需要调用一个提供者并在有状态的小部件中设置监听为真,比如

var model = Model.of(context, listen = true); 列表元素 = model.elements;

这里元素变量将在提供者中的元素具有新值时发生变化

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM