为什么要为订阅和 ChangeNotifier 实现 didUpdateWidget?

nio*_*ode 1 provider flutter

我创建了一个自定义小部件,它监听ChangeNotifier并在通知程序触发时调用提供的回调。这用于在通知程序更改时执行一次性任务,例如导航。

一切似乎都工作正常,但偶然我偶然发现了这样的文档didUpdateWidget

如果 State 的构建方法依赖于一个本身可以更改状态的对象,例如 ChangeNotifier 或 Stream,或者可以订阅以接收通知的其他对象,那么请确保在 initState、didUpdateWidget 和 dispose 中正确订阅和取消订阅:

  • 在initState中,订阅该对象。
  • 在 didUpdateWidget 中,如果更新的小部件配置需要替换对象,则取消订阅旧对象并订阅新对象。
  • 在处置中,取消订阅该对象。

我处理第一点和最后一点的原因很明显,但是有人可以解释一下为什么我也必须实施吗didUpdateWidget?如果我不这样做,会出现什么问题?

额外问题:我还没有在我的应用程序中使用提供程序。它是否提供了开箱即用的类似功能?我找不到这样的东西。

我的小部件代码:

class ChangeNotifierListener<T extends ChangeNotifier> extends StatefulWidget {
  final Widget child;
  final T changeNotifier;
  final void Function(T changeNotifier) onChanged;

  ChangeNotifierListener(
      {@required this.child,
      @required this.changeNotifier,
      @required this.onChanged});

  @override
  _ChangeNotifierListenerState createState() =>
      _ChangeNotifierListenerState<T>();
}

class _ChangeNotifierListenerState<T extends ChangeNotifier>
    extends State<ChangeNotifierListener<T>> {
  VoidCallback _callback;

  @override
  Widget build(BuildContext context) => widget.child;

  @override
  void initState() {
    super.initState();
    _callback = () {
      widget.onChanged(widget.changeNotifier);
    };
    widget.changeNotifier.addListener(_callback);
  }

  @override
  void dispose() {
    widget.changeNotifier.removeListener(_callback);
    super.dispose();
  }
}
Run Code Online (Sandbox Code Playgroud)

Rém*_*let 5

文档的这一部分是关于如何使用不同的参数重建您的小部件。

例如,对于StreamBuilder,第一个构建可能类似于:

StreamBuilder(
  stream: Stream.value(42),
  builder: ...
)
Run Code Online (Sandbox Code Playgroud)

然后有些东西发生了变化,并StreamBuilder用以下命令重建:

StreamBuilder(
  stream: Stream.value(21),
  builder: ...
)
Run Code Online (Sandbox Code Playgroud)

在这种情况下,stream改变了。因此,StreamBuilder需要停止听旧的Stream并听新的。

这可以通过以下方式完成didUpdateWidget

StreamSubscription<T> subscription;

@override
void didUpdateWidget(StreamBuilder<T> oldWidget) {
  super.didUpdateWidget(oldWidget);
  if (widget.stream != oldWidget.stream) {
    subscription?.cancel();
    subscription = widget.stream?.listen(...);
  }
}
Run Code Online (Sandbox Code Playgroud)

相同的逻辑适用于ChangeNotifier任何其他可观察的对象。