Comments (21)
@dshukertjr Oh yeah
It works now perfectly, thank you 🙏
from supabase-dart.
Realtime seems to close on its own when StreamBuilder
is quickly rebuilt as stated here, so will keep this issue opened until we can properly fix that issue.
from supabase-dart.
Thanks for opening this issue. Please do follow the issue template so that we can reproduce this issue on our end. Update events seem to work on my end. If you could share a minimal code snippet to reproduce this issue, that would be great.
from supabase-dart.
here is the code of that
StreamBuilder<List<Map<String, dynamic>>>(
stream: DatabaseHelper()
.client
.from("Questions")
.stream()
.order("timestamp")
.execute(),
builder: (context, questions) {
if (!questions.hasData) {
return const Center(child: CupertinoActivityIndicator());
}
List<Question> questionsList =
questions.data!.map((e) => Question.fromJson(e)).toList();
return Expanded(
flex: 1,
child: ListView.builder(
shrinkWrap: true,
physics: const AlwaysScrollableScrollPhysics(),
controller: questionsAnswersController.scrollController,
itemCount: questionsList.length,
itemBuilder: (_, index) {
return StreamBuilder<List<Map<String, dynamic>>>(
stream: DatabaseHelper()
.client
.from(
"IndividualProfile:userId=eq.${questionsList[index].authorId}")
.stream()
.order("timestamp")
.limit(1)
.execute(),
builder: (context, profile) {
if (!profile.hasData) {
return const Center(child: SizedBox());
}
if (profile.hasError || profile.error != null) {
return const Text("Text");
}
if (profile.data!.isEmpty) {
return Container();
}
final dataProfile = profile.data!.first;
IndividualProfile individualProfile =
IndividualProfile.fromJson(dataProfile);
return widgetCard(
individualProfile, questionsList[index]);
},
);
},
),
);
}),
from supabase-dart.
@akram-95
Okay, I am able to reproduce it. I haven't been able to dig all the way down to the cause of this, but my guess is that it is related to this characteristics of Supabase
While the client may join any number of topics on any number of channels, the client may only hold a single subscription for each unique topic at any given time. When attempting to create a duplicate subscription, the server will close the existing channel, log a warning, and spawn a new channel for the topic. The client will have their channel.onClose callbacks fired for the existing channel, and the new channel join will have its receive hooks processed as normal.
From supabase-js readme.md
When the outer StreamBuilder
rebuilds, the inner StreamBuilders
are quickly rebuilt again, causing the sockets to quickly disconnect and reconnect again.
You can probably avoid this from happening if you could combine the two Streams
together to make sure this quick reconnection does not happen. I'm thinking something like the following. Note that this code is just a quick example that I wrote up, so might not work, but hopefully you can understand the idea.
This not only solves the problem you are facing, it gets rid of the flash that you experience whenever the parent widget rebuilds!
class Example extends StatefulWidget {
const Example({Key? key}) : super(key: key);
@override
_ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
late StreamSubscription _questionsListener;
// Stores the StreamSubscription where the userId is the key of the map
final Map<String, StreamSubscription> _profileSubscriptions = {};
// Stores the profile data of users where the key is their uid
final Map<String, Profile> _profiles = {};
final List<Question> _questions = [];
@override
Widget build(BuildContext context) {
return ListView.builder(itemBuilder: (context, index) {
final question = _questions[index];
return ListTile(
title: Text(question.title),
subtitle: Text(_profiles[question.authorId].name),
);
});
}
void _loadData() {
_questionsListener =
supabase.from('questions').stream().execute().listen((questions) {
_questions.addAll(Question.fromEvent(questions));
for (final question in questions) {
// Make sure only create the listener if a listener for the user has not been created yet
if (_profileSubscriptions[question['authorId']] == null) {
_profileSubscriptions[question['authorId']] = supabase
.from('IndividualProfile:userId=eq.${question['authorId']}')
.stream()
.execute()
.listen((event) {
final profile = Profile.fromEvent(event);
_profiles[profile.uid] = profile;
setState(() {});
});
}
setState(() {});
}
});
}
@override
void initState() {
_loadData();
super.initState();
}
@override
void dispose() {
_questionsListener.cancel();
for (final profileListener in _profileSubscriptions.values) {
profileListener.cancel();
}
super.dispose();
}
}
from supabase-dart.
Will dig deeper into this issue and share anything that I find here in the meanwhile!
from supabase-dart.
@dshukertjr Thank you so much for your support , but unfortunately it doesn't work and I did notice that when I update an array of varchar , it's not empty, it has the value [archa]
From where does it come ?
from supabase-dart.
when i update the array of char stars , in the result of execution it's true but in the listen of stream, i get the value [archa]
from supabase-dart.
Could you please share your table schema as well as the code you are using to produce the above log?
from supabase-dart.
Yeah please https://user-images.githubusercontent.com/55693316/130314658-f0b05b39-ab8f-4817-8ad1-1f9382754fdd.MOV
from supabase-dart.
@dshukertjr On the table the array stars is empty and when I update it , it becomes an new user Id when I want to listen to that I get [archa]
from supabase-dart.
the code for updating a Question
the code for listening to changes in the table Questions
from supabase-dart.
When you share your code, it is better to share it as text rather than image. That way other people can just copy and paste!
In the first code block, could you share what you are assigning to newQuestionValue
?
Also, is the reason why you have stars
and likes
etc... in Questions
table because that is how you used to do it in Firebase? Typically in SQL database, you do it like this? With this approach, you can utilize row level security as well. With your current setup, I think it's impossible or at least pretty hard to make it completely secure with row level security. You always face malicious user wiping the star
or like
data.
from supabase-dart.
i used stars and likes as an array for every Question , that's the only reason , i did it always like that using firebase
that's the code for the first Block
Future setLikeQuestionBySupabase(
Question question, likeArt likeart, String followerId) async {
var result = await client
.from("Questions")
.select()
.eq("questionId", question.questionId)
.single()
.execute();
if (result.error != null) {
return ProcessState.failed;
}
Question newQuestionValue = Question.fromJson(result.toJson()["data"]);
if (likeart == likeArt.star) {
newQuestionValue.dislikes.removeWhere((element) => element == followerId);
newQuestionValue.likes.removeWhere((element) => element == followerId);
if (newQuestionValue.stars.contains(followerId)) {
newQuestionValue.stars.removeWhere((element) => element == followerId);
} else {
newQuestionValue.stars.add(followerId);
}
}
if (likeart == likeArt.like) {
newQuestionValue.stars.removeWhere((element) => element == followerId);
newQuestionValue.dislikes.removeWhere((element) => element == followerId);
if (newQuestionValue.likes.contains(followerId)) {
newQuestionValue.likes.removeWhere((element) => element == followerId);
} else {
newQuestionValue.likes.add(followerId);
}
}
if (likeart == likeArt.dislike) {
newQuestionValue.likes.removeWhere((element) => element == followerId);
newQuestionValue.stars.removeWhere((element) => element == followerId);
if (newQuestionValue.dislikes.contains(followerId)) {
newQuestionValue.dislikes
.removeWhere((element) => element == followerId);
} else {
newQuestionValue.dislikes.add(followerId);
}
}
result = await client
.from("Questions")
.update(newQuestionValue.toJson())
.eq("questionId", newQuestionValue.questionId)
.execute();
print(result.data);
if (result.error != null) {
return ProcessState.failed;
}
return ProcessState.successful;
}
from supabase-dart.
@akram-95
Thanks for sharing the code! I found a bug within realtime-dart
that is causing the array value not being returned correctly and returning ['archa'] instead. Have to go to bed for now, but will fix it first thing in the morning! Thanks for the patients!
from supabase-dart.
@dshukertjr Nice to hear
Good night and thank you for your support
from supabase-dart.
@akram-95
With the latest update, you should be able to receive array values correctly. Thanks for your patients!
from supabase-dart.
Realtime seems to close on its own when
StreamBuilder
is quickly rebuilt as stated here, so will keep this issue opened until we can properly fix that issue.
Any updates?
from supabase-dart.
Hi @elhe26
We have been busy adding WALRUS support to the realtime client, so there has not been any updates on this issue, but did you try the workaround? It is generally not a very good idea to nest StreamBuilders anyway in my opinion because every time the parent rebuilds, the child has to rebuild again and has to start from ConnectionState.waiting
.
from supabase-dart.
stream()
should not be called directly on the build
function. When it's rebuilt, the stream is executed every time the screen is rebuilt (since you're calling the function on build time). The stream()
will also rebuilt when you hot realod, so this is not an issue with the current stream()
implementation.
What you can do is:
class Example extends StatefulWidget {
const Example({Key? key}) : super(key: key);
@override
_ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
late Stream stream1;
late Stream stream2;
@override
void initState() {
super.initState();
stream1 = DatabaseHelper()
.client
.from("Questions")
.stream()
.order("timestamp")
.execute();
stream2 = DatabaseHelper()
.client
.from("IndividualProfile:userId=eq.${questionsList[index].authorId}")
.stream()
.order("timestamp")
.limit(1)
.execute();
}
@override
void dispose() {
// there isn't such thing as disposing streams. this is handled internally
super.dispose();
}
@override
Widget build(BuildContext context) {
return ListView.builder(itemBuilder: (context, index) {
final question = _questions[index];
StreamBuilder<List<Map<String, dynamic>>>(
stream: stream1,
builder: (context, questions) {
if (!questions.hasData) {
return const Center(child: CupertinoActivityIndicator());
}
List<Question> questionsList =
questions.data!.map((e) => Question.fromJson(e)).toList();
return Expanded(
flex: 1,
child: ListView.builder(
shrinkWrap: true,
physics: const AlwaysScrollableScrollPhysics(),
controller: questionsAnswersController.scrollController,
itemCount: questionsList.length,
itemBuilder: (_, index) {
return StreamBuilder<List<Map<String, dynamic>>>(
stream: stream2,
builder: (context, profile) {
if (!profile.hasData) {
return const Center(child: SizedBox());
}
if (profile.hasError || profile.error != null) {
return const Text("Text");
}
if (profile.data!.isEmpty) {
return Container();
}
final dataProfile = profile.data!.first;
IndividualProfile individualProfile =
IndividualProfile.fromJson(dataProfile);
return widgetCard(
individualProfile, questionsList[index]);
},
);
},
),
);
});
});
}
}
Can this be closed?
from supabase-dart.
Closing as solved!
from supabase-dart.
Related Issues (20)
- Status 404 with returned public url HOT 2
- Resending OTP HOT 2
- Functions-dart repo is not public yet HOT 1
- Dart library rework HOT 1
- Token leaked in network tab HOT 3
- can not update phone number via auth.update() HOT 1
- getx +supabase HOT 4
- Implementation `Column is in an array` HOT 3
- Dart client unable utilize eq() or match() to retrieve a row from table
- RealtimeSubscription Unhandled Exception: type 'Null' is not a subtype of type 'List<dynamic>' in type cast HOT 10
- Int column turned to String in realtime listening (for one row) HOT 6
- Boolean values comes with null in realtime events HOT 2
- Bug: flags field is missing on RLS-Realtime HOT 13
- Kong Error : No Api key found in request HOT 7
- On Stream: The new updated value/row is always replacing the first element of return List of rows. HOT 1
- Can't use `StreamSubscription` with realtime streams HOT 1
- Supabase doesnot export gotrue_error.dart class HOT 1
- Kong Error : No Api key found in request HOT 2
- stream returns invalid response HOT 5
- Unhandled Exception with realtime rls HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from supabase-dart.