-
-
Notifications
You must be signed in to change notification settings - Fork 156
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
nested StreamBuilder bug report (using supabase: ^0.2.8 on Flutter project) #41
Comments
resend the images: |
Hi there,
|
Hi @JasonChiu-dev! Thanks for opening an issue here. Would you mind copy and pasting your code instead of attaching screenshots? That way we can copy and paste it locally to test it right away. If you have a public github repo with your code in it, sharing it here would be extremely helpful! Aside from the bug that is present on |
Yes, I can copy and pasting my code. Here is my sample code for test: import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:supabase/supabase.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: MyHomePage(title: 'Nested StreamBuilders Test Page'),
);
}
}
// Supabase
final _supabase = SupabaseClient('SupabaseURL', 'KEY');
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
int _counter = 0;
class _MyHomePageState extends State<MyHomePage> {
Future<void> _addOwner({required Owner owner}) async {
try {
final response = await _supabase.from('owners').insert({
'ownerId': owner.ownerId,
'ownerName': owner.ownerName,
}).execute();
if (response.error != null) {
// Error
print(response.error!.message);
}
} catch (e) {
print('ERROR: ' + e.toString());
}
}
// add a new record(Project) to the projects table.
Future<void> _addProject({required Project project}) async {
try {
final response = await _supabase.from('projects').insert({
'projectId': project.projectId,
'projectName': project.projectName,
'ownerId': project.ownerId,
}).execute();
if (response.error != null) {
// Error
print(response.error!.message);
}
} catch (e) {
print('ERROR: ' + e.toString());
}
}
Future<void> _incrementCounter() async {
print('FloatingActionButton onPressed: $_counter');
if (_counter.isEven) {
print('addOwner _counter.isEven: $_counter');
await _addOwner(
owner: Owner(
ownerId: _counter.toString(),
ownerName: _counter.toString() + '-owner',
),
);
} else {
print('addProject _counter.isNotEven: $_counter');
int num = _counter - 1;
await _addProject(
project: Project(
projectId: _counter.toString(),
projectName: _counter.toString() + '-project',
ownerId: num.toString(),
),
);
}
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: const NestedStream(),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
child: const Icon(Icons.add),
),
);
}
}
class NestedStream extends StatelessWidget {
const NestedStream({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
// stream-1
return StreamBuilder<List<Map<String, dynamic>>>(
stream: _supabase.from('owners').stream().order('ownerName').execute(),
builder: (context, ownerSnapshot) {
if (ownerSnapshot.hasError) {
return Center(
// To see if it is needed for the error dialog or not
child: Text(
ownerSnapshot.error.toString(),
),
);
}
print('(Owner) stream: ${ownerSnapshot.connectionState}');
if (!ownerSnapshot.hasData || ownerSnapshot.connectionState != ConnectionState.active) {
return const Center(child: CupertinoActivityIndicator());
}
print('ownerSnapshot.hasData, ' + ownerSnapshot.requireData.length.toString() + ' data.');
List<Owner> owners = _getOwnersFromQuery(ownerSnapshot.requireData);
// stream-2
return StreamBuilder<List<Map<String, dynamic>>>(
stream: _supabase.from('projects').stream().order('projectId').limit(50).execute(),
builder: (context, projectSnapshot) {
if (projectSnapshot.hasError) {
return Center(
child: Text(projectSnapshot.error.toString()),
);
}
print('(Project) stream: ${projectSnapshot.connectionState}');
if (!projectSnapshot.hasData || projectSnapshot.connectionState != ConnectionState.active) {
return const Center(child: CupertinoActivityIndicator());
}
print('projectSnapshot.hasData, ' + projectSnapshot.requireData.length.toString() + ' data.');
List<Project> projects = _getProjectsFromQuery(projectSnapshot.requireData);
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'owners.length = ${owners.length}',
style: Theme.of(context).textTheme.headline5,
),
const SizedBox(
height: 15.0,
),
Text(
'projects.length = ${projects.length}',
style: Theme.of(context).textTheme.headline5,
),
],
),
);
},
);
},
);
}
List<Owner> _getOwnersFromQuery(List<Map<String, dynamic>> snapshot) {
return snapshot.map((doc) {
return Owner.fromSnapshot(doc);
}).toList();
}
List<Project> _getProjectsFromQuery(List<Map<String, dynamic>> snapshot) {
return snapshot.map((doc) {
return Project.fromSnapshot(doc);
}).toList();
}
}
class Owner {
Owner({
this.id,
required this.ownerId,
required this.ownerName,
});
// id: generated by default as identity primary key. Automatically assign a sequential unique number to the column.
int? id;
String ownerId;
String ownerName;
Owner.fromSnapshot(Map<String, dynamic> snapshot)
: id = snapshot['id'], // Automatically assign a sequential unique number to the column and is primary key
ownerId = snapshot['ownerId'],
ownerName = snapshot['ownerName'];
}
class Project {
Project({
this.id,
required this.projectId,
required this.projectName,
required this.ownerId,
});
// id: generated by default as identity primary key. Automatically assign a sequential unique number to the column.
int? id;
String projectId;
String projectName;
String ownerId; // foreign key reference to TABLE owners.ownerId
Project.fromSnapshot(Map<String, dynamic> snapshot)
: id = snapshot['id'],
projectId = snapshot['projectId'],
projectName = snapshot['projectName'],
ownerId = snapshot['ownerId'];
} For your information. Jason |
Thanks @JasonChiu-dev! Did you have any chances to try out my workaround? |
Yes, I just try out the workaround you mentioned above and it works. Thanks for your help. |
@JasonChiu-dev Yes, I'm sure there is a bug causing supabase_dart to not work with nested StreamBuilders (not sure what the cause is. We would love to fix the bug at some point, but since nested StreamBuilders are generally not a very good practice even with Firebase because of the blinking effect, it is not the highest priority. If you could try to pinpoint the cause, that will be great! |
I will close this issue in favor of the issue here. |
OK. Thank you so much for your help. |
Bug report
nested StreamBuilder bug report (using supabase: ^0.2.8 on Flutter project)
Describe the bug
A clear and concise description of what the bug is.
I have the same Flutter project running on Firebase with nested StreamBuilders and it works very well and response immediately and correctly when I insert or update data to the Firebase. But when I transfer my Flutter project to Supabase, it works well and I found that Supabase is the good choice for migrating from Firebase to Supabase with RDBS. So I did more tests for my Flutter project on Supabase (which are the same actions running on Firebase), but I found the streams sometimes repose good but sometimes not work.
To Reproduce
Steps to reproduce the behavior, please provide code snippets or a repository:
![截圖 2021-10-22 上午11 30 25](https://user-images.githubusercontent.com/81674344/138389122-8e8a4ad9-10b1-44ef-95f6-9a8c7e18195f.png)
Here are my code snippets:
There are two tables in the database and I use nested StreamBuilder to get data from each table.
When I added the data to 'the first table - owners' the two streams work correctly, but when I added the data to 'the second table - projects' the streams no reaction even the data was really insert to the second table successfully (I checked the Supabase admin console).
here is the error data:
![截圖 2021-10-22 上午10 58 24](https://user-images.githubusercontent.com/81674344/138389261-6a8ec906-38d3-4e59-b300-8985ef25e41f.png)
![截圖 2021-10-22 上午10 58 36](https://user-images.githubusercontent.com/81674344/138389275-c7e2508a-bf3f-4653-b1da-7d2f3ce8eea3.png)
<img width="1231" alt="截圖 2021-10-22 上午10 57 43" src="https://user-images.githubuserco
ntent.com/81674344/138389231-5949a346-4778-4d5d-8226-529557035395.png">
Expected behavior
A clear and concise description of what you expected to happen.
Screenshots
If applicable, add screenshots to help explain your problem.
Just like what I get from Firebase with nested StreamBuilders for fetching data from database immediately and correctly.
The stream should response immediately and correctly when I insert or do any action to my database so that I can doing the correct operation for my project and database.
System information
![截圖 2021-10-22 上午11 30 52](https://user-images.githubusercontent.com/81674344/138389148-609d113a-c92c-47d6-8fff-c2bea2018d56.png)
## Additional contextAdd any other context about the problem here.
The text was updated successfully, but these errors were encountered: