Reputation: 63
I am a little bit confused on why a GraphQL query returning a list of items does not get updated. Say I have a list of three items, then I add another item and rebuild the widget. The widget still only shows the first three items, even though I can see that new item has been created in the database. I am unsure if this is a cache problem. I have tried to fetch data from the network only, but that does not work either.
The client used in the GraphQLProvider is instantiated like this:
Future<ValueNotifier<GraphQLClient>> _getClient() async {
final HttpLink httpLink = HttpLink(
Constants.apiURL,
defaultHeaders: {
'X-Parse-Application-Id': Constants.kParseApplicationId,
'X-Parse-Client-Key': Constants.kParseClientKey,
},
);
// initialize Hive and wrap the default box in a HiveStore
Directory directory = await pathProvider.getApplicationDocumentsDirectory();
final store = await HiveStore.open(path: directory.path);
return ValueNotifier(
GraphQLClient(
cache: GraphQLCache(store: store),
link: httpLink,
),
);
}
And the page looks like this. When a new forum post is created, setstate() is called and the widget rebuilds. However, the line List<dynamic> forumEntries = result.data?["getForumEntries"];
still returns the old list of data without the new entry. I have the same problem in a few other places as well.
class FeedWidget extends StatefulWidget {
const FeedWidget({Key? key}) : super(key: key);
@override
State<FeedWidget> createState() => _FeedWidgetState();
}
class _FeedWidgetState extends State<FeedWidget> {
final TextEditingController controller = TextEditingController();
void _createForumPost() async {
Map<String, dynamic> inputVariables = {
"questionText": controller.text,
};
GraphQLClient client = GraphQLProvider.of(context).value;
await client.query(
QueryOptions(
document: gql(GraphQLQueries.createForumPost),
variables: inputVariables,
),
);
setState(() {
controller.text = "";
});
}
@override
Widget build(BuildContext context) {
return Query(
options: QueryOptions(
fetchPolicy: FetchPolicy.networkOnly,
document: gql(GraphQLQueries.getForumEntries),
),
builder: (QueryResult result,
{VoidCallback? refetch, FetchMore? fetchMore}) {
if (result.hasException) {
return Text(result.exception.toString());
}
if (result.isLoading) {
return const Center(child: CircularProgressIndicator());
}
List<dynamic> forumEntries = result.data?["getForumEntries"];
return Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Row(
children: [
Expanded(
child: TextField(
controller: controller,
keyboardType: TextInputType.multiline,
maxLines: null,
autocorrect: false,
decoration: InputDecoration(
fillColor: Theme.of(context).colorScheme.surface,
labelText: "Content",
filled: true,
border: InputBorder.none,
),
),
),
const Padding(padding: EdgeInsets.symmetric(horizontal: 3)),
CustomIconButton(
padding: EdgeInsets.zero,
icon: const Icon(Icons.send),
onPressed: () => _createForumPost(),
),
],
),
const Padding(padding: EdgeInsets.only(bottom: 10)),
Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: forumEntries.length,
itemBuilder: (BuildContext context, int index) {
Map<String, dynamic> entry = forumEntries[index];
return ForumEntryWidget(entry);
},
),
),
],
);
},
);
}
}
Upvotes: 1
Views: 1422
Reputation: 2148
For people wondering why graphQL query still returns old value, even with a refresh (for instance with future provider in Riverpod).
Check the GraphQL cache used with your client :
return GraphQLClient(
cache: GraphQLCache(), <-- here
link: link,
);
You could in some case avoid using cache in options query :
final options = QueryOptions(
document: gql(query),
fetchPolicy: FetchPolicy.noCache, <-- here
);
Upvotes: 1
Reputation: 11
I was stuck on this and solved it easily using refetch functions returned by Query. As your CustomIconButton
are inside the Query, you can replace _createForumPost()
with refetch()
. In my case I use the RefreshIndicator
creating a function Future<void>
which calls the refetch
method.
@override
Widget build(BuildContext context) {
// resp = ListView();
return Scaffold(
body: Query(
options: QueryOptions(
document: gql(documentQ),
fetchPolicy: FetchPolicy.noCache,
cacheRereadPolicy: CacheRereadPolicy.ignoreAll,
optimisticResult: true),
builder: (QueryResult result,
{Refetch? refetch, FetchMore? fetchMore}) {
if (result.isLoading) {
return const Center(child: CircularProgressIndicator());
}
if (result.data == null) {
return const Center(child: Text('Nenhum tour por perto'));
}
return _toursView(result, refetch);
},
),
);
}
RefreshIndicator _toursView(QueryResult result, refetch) {
// print(result.data?['tourAll']);
Future<void> refresh(refetch) {
return refetch();
}
final toursList = result.data?['tourAll'];
return RefreshIndicator(
onRefresh: () => refresh(refetch),
child: ...
Upvotes: 1