docs: add advanced category, move optimistic updates & persisting queries to advanced

This commit is contained in:
Kingkor Roy Tirtho
2023-10-18 20:30:10 +06:00
parent 9660f573c3
commit 6708eabcb8
14 changed files with 144 additions and 277 deletions
@@ -1,6 +1,6 @@
---
title: Optimistic Updates
sidebar_position: 10
sidebar_position: 1
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
+128
View File
@@ -0,0 +1,128 @@
---
title: Persisting Queries
sidebar_position: 1
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
Implementing offline capabilites by your own can be hard to do (and maintain!!) so Fl-Query makes easier for developers to do it. Fl-Query uses [Hive](https://docs.hivedb.dev/#/) to persist queries to disk. Hive is a Open Source, "lightweight and buzzing-fast key-value database made for Flutter and Dart."
We're using hive because it supports storing unstructured data and the write speed is blazingly fast
But it is planned to support multiple types of Database for persisting using an Adapter pattern
### Persisting Queries
Queries can be persisted by passing `jsonConfig` argument to the `QueryBuilder` or `useQuery`. Persisted queries are stored in [hive](https://docs.hivedb.dev/) cache and are available even after the app is restarted
First make sure your custom data type is json serializable. You can use [json_serializable](https://pub.dev/packages/json_serializable) package to generate `toJson` and `fromJson` methods for your data type
```dart
import 'package:json_annotation/json_annotation.dart';
part 'todo.g.dart';
@JsonSerializable()
class Todo{
final String id;
final String title;
final bool completed;
Todo({
required this.id,
required this.title,
required this.completed,
});
factory Todo.fromJson(Map<String, dynamic> json) => _$TodoFromJson(json);
Map<String, dynamic> toJson() => _$TodoToJson(this);
}
```
<Tabs>
<TabItem value="vanilla" label="Vanilla">
```dart
QueryBuilder<Todo, HttpException>(
"todos",
() => api.getTodos(),
jsonConfig: JsonConfig(
fromJson: (json) => Todo.fromJson(json),
toJson: (todo) => todo.toJson(),
),
builder: (context, query) {
/* ... */
},
);
```
</TabItem>
<TabItem value="flutter_hooks" label="Flutter Hooks">
```dart
useQuery<Todo, HttpException>(
"todos",
() => api.getTodos(),
jsonConfig: JsonConfig(
fromJson: (json) => Todo.fromJson(json),
toJson: (todo) => todo.toJson(),
),
);
```
</TabItem>
</Tabs>
Right now due to lack of reflection support and compile time macros we're unable to serialize any data type on the fly.
That's why `JsonConfig` is required. Otherwise, a simple `persistToDisk: true` would have been enough
### Persisting InfiniteQueries
Just like `Query`, `InfiniteQuery` also accepts `jsonConfig` argument to persist page data to disk. With persisting `InfiniteQuery` you can achieve similar results like facebook/twitter's offline mode
<Tabs>
<TabItem value="vanilla" label="Vanilla">
```dart
InfiniteQueryBuilder<PagedPosts, ClientException, int>(
"posts",
(page) => api.getPostsPaginated(page),
nextPage: (lastPage, lastPageData) {
/// returning [null] will set [hasNextPage] to [false]
if (lastPageData.posts.length < 10) return null;
return lastPage + 1;
},
initialPage: 0,
jsonConfig: JsonConfig(
fromJson: (json)=> PagedPosts.fromJson(json),
toJson: (pagedPosts) => pagedPosts.toJson(),
),
builder: /*...*/
);
```
</TabItem>
<TabItem value="flutter_hooks" label="Flutter Hooks">
```dart
final query = useInfiniteQuery<PagedPosts, ClientException, int>(
"posts",
(page) => api.getPostsPaginated(page),
nextPage: (lastPage, lastPageData) {
/// returning [null] will set [hasNextPage] to [false]
if (lastPageData.posts.length < 10) return null;
return lastPage + 1;
},
initialPage: 0,
jsonConfig: JsonConfig(
fromJson: (json)=> PagedPosts.fromJson(json),
toJson: (pagedPosts) => pagedPosts.toJson(),
),
);
```
</TabItem>
</Tabs>
This will persist each available page to a HiveStore
+8
View File
@@ -0,0 +1,8 @@
{
"label": "Advanced",
"position": 3,
"link": {
"type": "generated-index",
"description": "Advanced caching and data manipulation techniques to make your app better"
}
}
+2 -54
View File
@@ -217,7 +217,7 @@ await Future.wait(
### Set page data manually
`InfiniteQuery` provides a method `InfiniteQuery.setPageData` to set page data manually. This can be useful if you want to set data after a mutation for [Optmisitc Updates](/docs/basics/OptimisticUpdates)
`InfiniteQuery` provides a method `InfiniteQuery.setPageData` to set page data manually. This can be useful if you want to set data after a mutation for [Optmisitc Updates](/docs/advanced/OptimisticUpdates)
```dart
query.setPageData(0, [...query.pages[0], newProduct])
@@ -309,56 +309,4 @@ final query = useInfiniteQuery<PagedProducts, ClientException, int>(
```
</TabItem>
</Tabs>
### Persisting InfiniteQueries
The `pages` data can be saved to disk to be loaded next time when the app starts to reduce loading time of your app. Just like [`Query`](/docs/basics/Queries#persisting-queries) persisted `InfiniteQuery`'s `pages` data are stored in [hive](https://docs.hivedb.dev/#/). This can be widely useful to add offline capabilities to the app
For this you need to pass a `jsonConfig: JsonConfig()` argument to `InfiniteQueryBuilder` or `useInfiniteQuery`. Also make sure your `DataType` is serializable to JSON. You can use [json_serializable](https://pub.dev/packages/json_serializable) to generate the code for you.
<Tabs>
<TabItem value="vanilla" label="Vanilla">
```dart
InfiniteQueryBuilder<PagedPosts, ClientException, int>(
"posts",
(page) => api.getPostsPaginated(page),
nextPage: (lastPage, lastPageData) {
/// returning [null] will set [hasNextPage] to [false]
if (lastPageData.posts.length < 10) return null;
return lastPage + 1;
},
initialPage: 0,
jsonConfig: JsonConfig(
fromJson: (json)=> PagedPosts.fromJson(json),
toJson: (pagedPosts) => pagedPosts.toJson(),
),
builder: /*...*/
);
```
</TabItem>
<TabItem value="flutter_hooks" label="Flutter Hooks">
```dart
final query = useInfiniteQuery<PagedPosts, ClientException, int>(
"posts",
(page) => api.getPostsPaginated(page),
nextPage: (lastPage, lastPageData) {
/// returning [null] will set [hasNextPage] to [false]
if (lastPageData.posts.length < 10) return null;
return lastPage + 1;
},
initialPage: 0,
jsonConfig: JsonConfig(
fromJson: (json)=> PagedPosts.fromJson(json),
toJson: (pagedPosts) => pagedPosts.toJson(),
),
);
```
</TabItem>
</Tabs>
This will persist each available page to a HiveStore
</Tabs>
+1 -1
View File
@@ -133,7 +133,7 @@ final mutation = useMutation<Map<String, dynamic>, dynamic, Map<String, dynamic>
</TabItem>
</Tabs>
> Learn how to use `onMutate` & `Query.setData` to implement [optimistic updates](/docs/basics/OptimisticUpdates)
> Learn how to use `onMutate` & `Query.setData` to implement [optimistic updates](/docs/advanced/OptimisticUpdates)
### Refetch Queries and InfiniteQueries on successful mutation
+1 -67
View File
@@ -190,70 +190,4 @@ useQuery<String, HttpException>(
</TabItem>
</Tabs>
Now these queries won't be executed as soon as they're mounted. Until `Query.refresh()` or `Query.fetch()` is called these will stay in initial state. If `initial` data was passed, it'll be used until the query is refreshed. Same goes for persisting queries
### Persisting Queries
Queries can be persisted by passing `jsonConfig` argument to the `QueryBuilder` or `useQuery`. Persisted queries are stored in [hive](https://docs.hivedb.dev/) cache and are available even after the app is restarted
First make sure your custom data type is json serializable. You can use [json_serializable](https://pub.dev/packages/json_serializable) package to generate `toJson` and `fromJson` methods for your data type
```dart
import 'package:json_annotation/json_annotation.dart';
part 'todo.g.dart';
@JsonSerializable()
class Todo{
final String id;
final String title;
final bool completed;
Todo({
required this.id,
required this.title,
required this.completed,
});
factory Todo.fromJson(Map<String, dynamic> json) => _$TodoFromJson(json);
Map<String, dynamic> toJson() => _$TodoToJson(this);
}
```
<Tabs>
<TabItem value="vanilla" label="Vanilla">
```dart
QueryBuilder<Todo, HttpException>(
"todos",
() => api.getTodos(),
jsonConfig: JsonConfig(
fromJson: (json) => Todo.fromJson(json),
toJson: (todo) => todo.toJson(),
),
builder: (context, query) {
/* ... */
},
);
```
</TabItem>
<TabItem value="flutter_hooks" label="Flutter Hooks">
```dart
useQuery<Todo, HttpException>(
"todos",
() => api.getTodos(),
jsonConfig: JsonConfig(
fromJson: (json) => Todo.fromJson(json),
toJson: (todo) => todo.toJson(),
),
);
```
</TabItem>
</Tabs>
Right now due to lack of reflection support and compile time macros we're unable to serialize any data type on the fly.
That's why `JsonConfig` is required. Otherwise, a simple `persistToDisk: true` would have been enough
Now these queries won't be executed as soon as they're mounted. Until `Query.refresh()` or `Query.fetch()` is called these will stay in initial state. If `initial` data was passed, it'll be used until the query is refreshed. Same goes for persisting queries
+1 -1
View File
@@ -1,6 +1,6 @@
{
"label": "Basics",
"position": 3,
"position": 2,
"link": {
"type": "generated-index",
"description": "Learn all the basic concepts of Fl-Query as well as the practical use-cases that can enhance your development experience"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"label": "Getting Started",
"position": 1,
"position": 1,
"link": {
"type": "generated-index"
}
+1 -2
View File
@@ -1,10 +1,9 @@
---
sidebar_position: 1
title: Overview
id: overview
---
## Overview
Asynchronous data caching, refetching & invalidation library for Flutter. FL-Query lets you manage & distribute your async data without touching any global state
Fl-Query makes asynchronous server state management a breeze in flutter
@@ -1,7 +0,0 @@
{
"label": "Tutorial - Extras",
"position": 4,
"link": {
"type": "generated-index"
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

@@ -1,55 +0,0 @@
---
sidebar_position: 1
---
# Manage Docs Versions
Docusaurus can manage multiple versions of your docs.
## Create a docs version
Release a version 1.0 of your project:
```bash
npm run docusaurus docs:version 1.0
```
The `docs` folder is copied into `versioned_docs/version-1.0` and `versions.json` is created.
Your docs now have 2 versions:
- `1.0` at `http://localhost:3000/docs/` for the version 1.0 docs
- `current` at `http://localhost:3000/docs/next/` for the **upcoming, unreleased docs**
## Add a Version Dropdown
To navigate seamlessly across versions, add a version dropdown.
Modify the `docusaurus.config.js` file:
```js title="docusaurus.config.js"
module.exports = {
themeConfig: {
navbar: {
items: [
// highlight-start
{
type: 'docsVersionDropdown',
},
// highlight-end
],
},
},
};
```
The docs version dropdown appears in your navbar:
![Docs Version Dropdown](./img/docsVersionDropdown.png)
## Update an existing version
It is possible to edit versioned docs in their respective folder:
- `versioned_docs/version-1.0/hello.md` updates `http://localhost:3000/docs/hello`
- `docs/hello.md` updates `http://localhost:3000/docs/next/hello`
@@ -1,88 +0,0 @@
---
sidebar_position: 2
---
# Translate your site
Let's translate `docs/intro.md` to French.
## Configure i18n
Modify `docusaurus.config.js` to add support for the `fr` locale:
```js title="docusaurus.config.js"
module.exports = {
i18n: {
defaultLocale: 'en',
locales: ['en', 'fr'],
},
};
```
## Translate a doc
Copy the `docs/intro.md` file to the `i18n/fr` folder:
```bash
mkdir -p i18n/fr/docusaurus-plugin-content-docs/current/
cp docs/intro.md i18n/fr/docusaurus-plugin-content-docs/current/intro.md
```
Translate `i18n/fr/docusaurus-plugin-content-docs/current/intro.md` in French.
## Start your localized site
Start your site on the French locale:
```bash
npm run start -- --locale fr
```
Your localized site is accessible at `http://localhost:3000/fr/` and the `Getting Started` page is translated.
:::caution
In development, you can only use one locale at a same time.
:::
## Add a Locale Dropdown
To navigate seamlessly across languages, add a locale dropdown.
Modify the `docusaurus.config.js` file:
```js title="docusaurus.config.js"
module.exports = {
themeConfig: {
navbar: {
items: [
// highlight-start
{
type: 'localeDropdown',
},
// highlight-end
],
},
},
};
```
The locale dropdown now appears in your navbar:
![Locale Dropdown](./img/localeDropdown.png)
## Build your localized site
Build your site for a specific locale:
```bash
npm run build -- --locale fr
```
Or build your site to include all the locales at once:
```bash
npm run build
```