flutter - 在StreamBuilder中使用选择器(提供程序)时,不需要的小部件重新生成

标签 flutter dart flutter-web flutter-provider

我正在使用Selector,当Bloc中的数据更改时,它会重新生成。这可以正常工作,但是当数据更改时,它会重新加载整个树,而不仅仅是Selector内部的构建器。

就我而言,选择器位于StreamBuilder中。我需要这个,因为流已连接到API。因此,在流中,我正在构建一些小部件,其中之一是Selector。 Selector重建依赖于Stream中数据的窗口小部件。

这是我的代码。我不想一次又一次地调用Stream。另外,还会调用Stream,因为每次重新生成选择器小部件时都会调用build

main.dart

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MultiProvider(providers: [
        ChangeNotifierProvider<DataBloc>(
          create: (_) => DataBloc(),
        )
      ], child: ProviderTest()),
    );
  }
}

class ProviderTest extends StatefulWidget {
  @override
  _ProviderTestState createState() => _ProviderTestState();
}

class _ProviderTestState extends State<ProviderTest> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: <Widget>[
          Text("Outside Stream Builder"),
          StreamBuilder(
            stream: Provider.of<DataBloc>(context).getString(),
            builder: (_, AsyncSnapshot<String> snapshot) {
              if (snapshot.hasData) {
                return Column(
                  children: <Widget>[
                    Text("Widget Generated by Stream Data"),
                    Text("Data From Strem : " + snapshot.data),
                    RaisedButton(
                        child: Text("Reload Select"),
                        onPressed: () {
                          Provider.of<DataBloc>(context, listen: false).changeValue(5);
                        }),
                    Selector<DataBloc, int>(
                        selector: (_, val) =>
                            Provider.of<DataBloc>(context, listen: false).val,
                        builder: (_, val, __) {
                          return Container(
                            child: Text(val.toString()),
                          );
                        }),
                  ],
                );
              }

              return Container();
            },
          )
        ],
      ),
    );
  }
}

bloc.dart
import 'package:flutter/foundation.dart';

class DataBloc with ChangeNotifier {

  int _willChange = 0;

  int get val => _willChange;

  void changeValue(int val){
    _willChange++;
    notifyListeners();
  }

  Stream<String> getString() {
    print("Stream Called");
    return Stream.fromIterable(["one", "two", "three"]);
  }

}

另外,如果我删除StreamBuilder,则Selector的行为应与假定的一样。为什么在这种情况下StreamBuilder会重建?反正是有防止这种情况发生的吗?

最佳答案

根据共享的代码,您可以在initState上创建Stream的侦听器,以更新保留了数据最新版本的变量,然后使用该变量填充小部件。这样,流将仅在第一次加载小部件时订阅,而不会在重新构建时订阅。我没有您的项目,因此无法直接测试。但是请尝试一下。

基于您的代码的代码示例

class ProviderTest extends StatefulWidget {
  @override
  _ProviderTestState createState() => _ProviderTestState();
}

class _ProviderTestState extends State<ProviderTest> {
  String _snapshotData;

  @override
  void initState() {
    listenToGetString();
    super.initState();
  }

  void listenToGetString(){
    Provider.of<DataBloc>(context).getString().listen((snapshot){
      setState(() {
        _snapshotData = snapshot.data;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: <Widget>[
          Text("Outside Stream Builder"),
          Column(
            children: <Widget>[
              Text("Widget Generated by Stream Data"),
              Text("Data From Strem : " + _snapshotData),
              RaisedButton(
                child: Text("Reload Select"),
                onPressed: () {
                  Provider.of<DataBloc>(context, listen: false).changeValue(5);
                }
              ),
              Selector<DataBloc, int>(
                selector: (_, val) =>
                  Provider.of<DataBloc>(context, listen: false).val,
                builder: (_, val, __) {
                  return Container(
                    child: Text(val.toString()),
                  );
                }
              ),
            ],
          )
        ],
      ),
    );
  }
}

关于flutter - 在StreamBuilder中使用选择器(提供程序)时,不需要的小部件重新生成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59570032/

相关文章:

android - 后退按钮不适用于 SafeArea View

pdf - 我想从PDF文件中获取总页数

flutter - 将 ListView 的最后一个元素固定到屏幕底部

swift - Flutter Desktop : Firebase Auth could not find a valid GoogleService-Info. plist

flutter - 如何更改 Flutter for web 字体?

list - 在flift中缓存两个列表

flutter - RangeError(索引):无效值:有效值范围为空:-1

dart - flutter 模糊叠加

string - 在Flutter Web中比较两个字符串/比较两个Cloud Firestore对象的documentID

flutter - Flutter 如何在所有平台(包括 Web)上播放音频