在StreamBuilder中使用选择器(提供程序)时,不需要的小部件重新生成 [英] Unnecessary Widget Rebuilds While Using Selector (Provider) inside StreamBuilder

查看:68
本文介绍了在StreamBuilder中使用选择器(提供程序)时,不需要的小部件重新生成的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am using a Selector which rebuilds when a data in Bloc changes. Which woks fine but when the data changes it reloads the whole tree not just the builder inside Selector.

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

In my case the selector is inside a StreamBuilder. I need this because the stream is connected to API. So inside the stream I am building some widget and One of them is Selector. Selector rebuilds widgets which is depended on the data from the Stream.

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

Here is My Code. I dont want the Stream to be called again and again. Also the Stream gets called because the build gets called every time selector widget rebuilds.

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会重建?反正是有防止这种情况发生的吗?

Also if I remove the StreamBuilder then the Selector acts like its suppose to. Why does StreamBuilder Rebuilds in this case? Is there anyway to prevent this?

推荐答案

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

Based on the code that you've shared, you can create a listener to your Stream on your initState that updates a variable that keeps the most recent version of your data, and then use that variable to populate your widgets. This way the Stream will only be subscribed to the first time the Widget loads, and not on rebuilds. I can't test it directly as I don't have your project. But please try it out.

基于您的代码的代码示例

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()),
                  );
                }
              ),
            ],
          )
        ],
      ),
    );
  }
}

这篇关于在StreamBuilder中使用选择器(提供程序)时,不需要的小部件重新生成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆