admin管理员组文章数量:1415645
I'm building a social feed. I have a view for the list of posts, and a view for creating a post. When the user creates a post, I want to submit it to my backend, make a callback to my setState callback in the views where posts are listed, and then pop the new post view off the widget tree with the result being that the post list view has been rebuilt, and in doing do, rebuilt the future builder getting new posts from the backend. For some reason, That's not working and I'm not sure why. I've even tried breaking the riverpod invocation into it's own function in my list posts class so that something would have to be explicitly invoked but it's not working.
social_feed.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:irc/features/social/views/social_post_create.dart';
//Import Providers
import 'package:irc/shared/pocketbase_provider.dart';
//Import Feature Widgets
import 'package:irc/features/social/widgets/social_tile.dart';
class SocialFeedScaffold extends ConsumerStatefulWidget {
const SocialFeedScaffold({super.key});
@override
ConsumerState<SocialFeedScaffold> createState() =>
_SocialFeedScaffoldConsumerState();
}
class _SocialFeedScaffoldConsumerState
extends ConsumerState<SocialFeedScaffold> {
void setStateCallback() => setState(() {});
@override
Widget build(BuildContext context) {
final pocketbase = ref.watch(pocketbaseProvider);
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(8.0),
child: SingleChildScrollView(
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: Text("What other researchers are talking about...",
style: GoogleFonts.cardo(
fontSize: 32, fontWeight: FontWeight.bold)),
),
// INLINE SOCIAL FEED
FutureBuilder(
future: pocketbase.collection('posts').getList(
perPage: 100, sort: '-created', expand: 'posted_by'),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
List postList = snapshot.data!.toJson()['items'];
return ListView.separated(
shrinkWrap: true,
itemCount: postList.length,
separatorBuilder: (context, index) =>
const SizedBox(height: 16),
itemBuilder: (BuildContext context, int index) {
return SocialTile(
postContent: postList[index]['post_content'],
postedBy: snapshot.data!.toJson()['items'][index]
['expand']['posted_by']['username']);
});
} else if (snapshot.connectionState ==
ConnectionState.waiting) {
return const CircularProgressIndicator();
} else if (snapshot.hasError) {
return Text(snapshot.error.toString());
} else {
return const CircularProgressIndicator();
}
}),
],
)),
),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.black,
child: const Icon(Icons.post_add, color: Colors.white),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => NewPostFormView(
setStateCallback: setStateCallback,
)));
}),
);
}
}
social_post_create.dart
import 'package:flutter/material.dart';
// You're not importing FLUTTER RIVERPOD, just riverpod and that's fricking your code.
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:irc/shared/pocketbase_provider.dart';
import 'package:pocketbase/pocketbase.dart';
import 'dart:ui';
class NewPostFormView extends ConsumerStatefulWidget {
// Class Constructor
const NewPostFormView({super.key, required this.setStateCallback});
// Class Fields
final void setStateCallback;
@override
ConsumerState<NewPostFormView> createState() =>
_newPostFormViewConsumerState();
}
class _newPostFormViewConsumerState extends ConsumerState<NewPostFormView> {
// State of the Widget
final TextEditingController userPostTextEditingController =
TextEditingController();
@override
Widget build(BuildContext context) {
final pb = ref.watch(pocketbaseProvider);
return Scaffold(
appBar: AppBar(title: const Text('New Post')),
body: Center(
child: Container(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
TextFormField(
controller: userPostTextEditingController,
maxLines: 10,
),
SizedBox(height: 30),
Row(mainAxisAlignment: MainAxisAlignment.center, children: [
ElevatedButton(
child: Text("Submit Post"),
onPressed: () {
pb.collection('posts').create(body: {
'post_content': userPostTextEditingController.text,
'posted_by': pb.authStore.record!.id,
'likes': 1
}).then((value) => widget.setStateCallback);
Navigator.of(context).pop();
}),
])
],
),
),
height: MediaQuery.of(context).size.height / 3,
width: MediaQuery.of(context).size.width / 3,
color: Colors.grey),
),
);
}
}
I'm building a social feed. I have a view for the list of posts, and a view for creating a post. When the user creates a post, I want to submit it to my backend, make a callback to my setState callback in the views where posts are listed, and then pop the new post view off the widget tree with the result being that the post list view has been rebuilt, and in doing do, rebuilt the future builder getting new posts from the backend. For some reason, That's not working and I'm not sure why. I've even tried breaking the riverpod invocation into it's own function in my list posts class so that something would have to be explicitly invoked but it's not working.
social_feed.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:irc/features/social/views/social_post_create.dart';
//Import Providers
import 'package:irc/shared/pocketbase_provider.dart';
//Import Feature Widgets
import 'package:irc/features/social/widgets/social_tile.dart';
class SocialFeedScaffold extends ConsumerStatefulWidget {
const SocialFeedScaffold({super.key});
@override
ConsumerState<SocialFeedScaffold> createState() =>
_SocialFeedScaffoldConsumerState();
}
class _SocialFeedScaffoldConsumerState
extends ConsumerState<SocialFeedScaffold> {
void setStateCallback() => setState(() {});
@override
Widget build(BuildContext context) {
final pocketbase = ref.watch(pocketbaseProvider);
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(8.0),
child: SingleChildScrollView(
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: Text("What other researchers are talking about...",
style: GoogleFonts.cardo(
fontSize: 32, fontWeight: FontWeight.bold)),
),
// INLINE SOCIAL FEED
FutureBuilder(
future: pocketbase.collection('posts').getList(
perPage: 100, sort: '-created', expand: 'posted_by'),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
List postList = snapshot.data!.toJson()['items'];
return ListView.separated(
shrinkWrap: true,
itemCount: postList.length,
separatorBuilder: (context, index) =>
const SizedBox(height: 16),
itemBuilder: (BuildContext context, int index) {
return SocialTile(
postContent: postList[index]['post_content'],
postedBy: snapshot.data!.toJson()['items'][index]
['expand']['posted_by']['username']);
});
} else if (snapshot.connectionState ==
ConnectionState.waiting) {
return const CircularProgressIndicator();
} else if (snapshot.hasError) {
return Text(snapshot.error.toString());
} else {
return const CircularProgressIndicator();
}
}),
],
)),
),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.black,
child: const Icon(Icons.post_add, color: Colors.white),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => NewPostFormView(
setStateCallback: setStateCallback,
)));
}),
);
}
}
social_post_create.dart
import 'package:flutter/material.dart';
// You're not importing FLUTTER RIVERPOD, just riverpod and that's fricking your code.
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:irc/shared/pocketbase_provider.dart';
import 'package:pocketbase/pocketbase.dart';
import 'dart:ui';
class NewPostFormView extends ConsumerStatefulWidget {
// Class Constructor
const NewPostFormView({super.key, required this.setStateCallback});
// Class Fields
final void setStateCallback;
@override
ConsumerState<NewPostFormView> createState() =>
_newPostFormViewConsumerState();
}
class _newPostFormViewConsumerState extends ConsumerState<NewPostFormView> {
// State of the Widget
final TextEditingController userPostTextEditingController =
TextEditingController();
@override
Widget build(BuildContext context) {
final pb = ref.watch(pocketbaseProvider);
return Scaffold(
appBar: AppBar(title: const Text('New Post')),
body: Center(
child: Container(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
TextFormField(
controller: userPostTextEditingController,
maxLines: 10,
),
SizedBox(height: 30),
Row(mainAxisAlignment: MainAxisAlignment.center, children: [
ElevatedButton(
child: Text("Submit Post"),
onPressed: () {
pb.collection('posts').create(body: {
'post_content': userPostTextEditingController.text,
'posted_by': pb.authStore.record!.id,
'likes': 1
}).then((value) => widget.setStateCallback);
Navigator.of(context).pop();
}),
])
],
),
),
height: MediaQuery.of(context).size.height / 3,
width: MediaQuery.of(context).size.width / 3,
color: Colors.grey),
),
);
}
}
Share
Improve this question
asked Feb 4 at 17:49
DJ KDJ K
13 bronze badges
1 Answer
Reset to default 0You are using riverpod, thus you should not use setState(). Instead of that, you should refresh the page using riverpod, just make:
ref.refresh(pocketbaseProvider);
And the page will be refreshed reloading all data.
Anyway I think you should not make that approach. First of all write down a new provider that fetches data from remote like this:
@riverpod
class PocketBaseProvider extends _$PocketBaseProvider{
@override
Future<List<Post>> build() => _fetch();
Future<List<Post>> _fetch() async {
state = const AsyncValue.loading();
final service = ref.watch(baasSDKProvider);
state = await AsyncValue.guard(
() async => service.findAll() );
return state.value!;
}
}
(take care of exceptions)
Then your widget should be like this:
class SocialFeedScaffold extends HookConsumerWidget {
const SocialFeedScaffold ({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final myLocalStateToHandle = useState(false);
final state = ref.watch(pocketBaseProvider);
return switch (state) {
AsyncError<bool>(:final error) => Center(
child: Text(error.toString()),
),
AsyncData<bool>(:final value) =>
_buildWithData(context,ref, value, myLocalStateToHandle),
_ => const Center(
child: CircularProgressIndicator(),
),
};
}
Then in the method _buildWithData()
you will build your interface using the data from the provider:
Widget _buildWithData(BuildContext context, WidgetRef ref,
List<Post> value, bool myLocalStateToHandle) {
.....
if ( myBool ) {
myLocalStateToHandle.value = .... ; //this would refresh the page
}
}
Now, if you want to re-read all data from baasSDKProvider , you can make ref.refresh(baasSDKProvider)
in a callback (always in a callback! never in the build()
method) of your interface, for example in a simple button for refreshing.
本文标签:
版权声明:本文标题:flutter - SetState callback in parent widget does not refresh riverpod-based Future builder when returning to view - Stack Overf 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1745242132a2649391.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论