I have a StreamBuilder and an int To increment number to do that I use setState function. And the problem is the StreamBuilder always getting new data every time setState is accur is there anyway to make the StreamBuilder not affect by setState every time the setState accur. To summarise is that Stop StreamBuilder from getting new data from backend every time when using setstate
full code
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/material.dart';
class StreamBuildTest2 extends StatefulWidget {
const StreamBuildTest2({super.key});
@override
State<StreamBuildTest2> createState() => _StreamBuildTest2State();
}
class _StreamBuildTest2State extends State<StreamBuildTest2> {
String userUid = FirebaseAuth.instance.currentUser!.uid;
final FirebaseStorage storage = FirebaseStorage.instance;
//Variable to increment number
int number = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
//The StreamBuilder that’s getting new data every time setState accur
body: StreamBuilder<DocumentSnapshot>(
stream: FirebaseFirestore.instance
.collection('users')
.doc(userUid)
.snapshots(),
builder: (context, snapshot) {
//Data from firebase backend
var fullName = snapshot.data?.get('fullName');
var email = snapshot.data?.get('email');
var profileUrl = snapshot.data?.get('profileUrl');
//
if (snapshot.connectionState == ConnectionState.waiting) {
return Container();
}
return Column(
children: [
//To get user profile
FutureBuilder(
future: downloadURL(profileUrl),
builder:
(BuildContext context, AsyncSnapshot<String> snapshot) {
if (snapshot.connectionState == ConnectionState.done &&
snapshot.hasData) {
return SizedBox(
height: 110,
width: 110,
child: FittedBox(
fit: BoxFit.contain,
//The user profile always getting new data every time setState accur
child: CircleAvatar(
backgroundColor: Colors.transparent,
backgroundImage: NetworkImage(snapshot.data!),
radius: 10.0,
),
),
);
}
if (snapshot.connectionState == ConnectionState.waiting ||
snapshot.hasData) {
return Container();
}
return Container();
},
),
Text(fullName),
Text(email),
Text(number.toString()),
//Here’s the setState
ElevatedButton(
onPressed: () => setState(() {
number += 1;
}),
style: ElevatedButton.styleFrom(
foregroundColor: Colors.black,
backgroundColor: Colors.grey,
elevation: 0.0,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.zero,
),
),
child: const Text('SetState Button'),
),
],
);
},
),
);
}
//Doesn’t matter here
Future<String> downloadURL(String file) async {
try {
String downloadURL =
await storage.ref('usersProfile/$file').getDownloadURL();
print(downloadURL);
return downloadURL;
} on FirebaseException catch (e) {
print(e);
}
return downloadURL(file);
}
}
feel free to Modified my code
Problem
The offsetNotifier can change but when I use onPanUpdate: _offsetNotifier,
I don’t want the FutureBuilder to change as well
final ValueNotifier<Offset> offsetNotifier = ValueNotifier(const Offset(0, 0));
void _offsetNotifier(DragUpdateDetails details) => offsetNotifier.value += details.delta;
ValueListenableBuilder(
valueListenable: offsetNotifier,
builder: (_, value, __) {
return Positioned(
left: offsetNotifier.value.dx,
top: offsetNotifier.value.dy,
child: FutureBuilder(
future: downloadURL(profileUrl),
builder: (BuildContext context,
AsyncSnapshot<String> snapshot) {
if (snapshot.connectionState == ConnectionState.done && snapshot.hasData) {
return CircleAvatar(
backgroundColor: Colors.transparent,
backgroundImage: NetworkImage(snapshot.data!),
radius: 10.0,
);
}
return Container();
}),
);
}),
Future<String> downloadURL(String file) async {
try {
String downloadURL =
await storage.ref('widgetsProfile/$file').getDownloadURL();
print(downloadURL);
return downloadURL;
} on FirebaseException catch (e) {
print(e);
}
return downloadURL(file);
}
}
You can also use ValueNotifier and ValueListenableBuilder to avoid rebuilding your entire widget to a _counter notifier, you can try that dartpad example
https://dartpad.dev/?id=1e52b13f6a9727e541baa74b58b1b558
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
final String title;
const MyHomePage({
Key? key,
required this.title,
}) : super(key: key);
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final ValueNotifier<int> _counterNotifier = ValueNotifier(0);
void _increment() => _counterNotifier.value = _counterNotifier.value + 1;
void _decrement() => _counterNotifier.value = _counterNotifier.value - 1;
@override
Widget build(BuildContext context) {
debugPrint('this does not re-render');
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'You have pushed the button this many times:',
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextButton(
onPressed: _decrement,
child: const Icon(Icons.remove),
),
SizedBox(
width: 48,
child: Center(
child: ValueListenableBuilder(
valueListenable: _counterNotifier,
builder: (_, count, __) {
return Text(
'$count',
style: Theme.of(context).textTheme.headlineMedium,
);
},
),
),
),
TextButton(
onPressed: _increment,
child: const Icon(Icons.add),
),
],
),
],
),
),
);
}
}