Skip to content

Commit 02a7b98

Browse files
committed
docs: updated documentation
1 parent 7dd59cd commit 02a7b98

14 files changed

+268
-83
lines changed

docs/docs/Advanced/index.md renamed to docs/docs/Advanced/index.mdx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
sidebar_position: 7
33
---
44

5+
import DocCardList from "@theme/DocCardList";
6+
57
# Advanced
68

79
Read more about how `rtk-query-loader` actually works.
10+
11+
<DocCardList />
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
sidebar_position: 6
3+
---
4+
5+
# aggregateToQuery
6+
7+
Aggregated a set of `UseQueryResult` into a single query.
8+
9+
:::caution
10+
`aggregateToQuery` does not add any `data` to the resulting query. You will have to do that manually afterwards.
11+
:::
12+
13+
```typescript
14+
import {
15+
aggregateToQuery,
16+
UseQueryResult,
17+
} from "@ryfylke-react/rtk-query-loader";
18+
19+
const queries = [
20+
useQueryOne(),
21+
useQueryTwo(),
22+
useQueryThree(),
23+
] as const;
24+
25+
const query: UseQueryResult<unknown> = {
26+
...aggregateToQuery(queries),
27+
data: queries.map((query) => query.data),
28+
};
29+
```

docs/docs/Exports/consumer-props.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
---
2+
sidebar_position: 5
3+
---
4+
5+
# ConsumerProps
6+
7+
Helper for typing your expected consumer props for the loader.
8+
9+
```typescript
10+
type PokemonLoaderProps = ConsumerProps<{
11+
name: string;
12+
}>;
13+
14+
const pokemonLoader = createLoader({
15+
queriesArg: (props: PokemonLoaderProps) => props.name,
16+
useQueries: (name) => ({
17+
queries: { pokemon: useGetPokemon(name) },
18+
}),
19+
});
20+
21+
// pokemonLoader can now we used by any component
22+
// that accepts a prop `name` of type `string`.
23+
24+
type PokemonComponentProps = {
25+
name: string;
26+
size: number;
27+
}; //
28+
29+
type OtherPokemonComponentProps = {
30+
name: string;
31+
}; //
32+
33+
type IncompatibleProps = {
34+
pokemonName: string;
35+
}; //
36+
```

docs/docs/Exports/create-loader.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,6 @@ const loader = createLoader({
3939
});
4040
```
4141

42-
A `Loader` takes ownership over...
43-
44-
- Data-loading
45-
- Data-transformation
46-
- Fetch-state rendering
47-
4842
:::caution Using version `0.3.51` or earlier?
4943
Please refer to the [**migration guide**](../Migrations/v0.x).
5044
:::

docs/docs/Exports/index.md renamed to docs/docs/Exports/index.mdx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@
22
sidebar_position: 6
33
---
44

5+
import DocCardList from "@theme/DocCardList";
6+
57
# Exports
68

79
Describes the different exports and their related types.
810

911
All the types can be found [here](https://github.com/ryfylke-react-as/rtk-query-loader/blob/main/src/types.ts).
12+
13+
<DocCardList />

docs/docs/Features/custom-loader.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,85 @@ sidebar_position: 5
44

55
# Custom `loaderComponent`
66

7+
A `loaderComponent` is the component that determines what to render given the aggregated query status, when using `withLoader`.
8+
9+
```typescript title="loaderComponent Props"
10+
export type CustomLoaderProps<T = unknown> = {
11+
/** The joined query for the loader */
12+
query: UseQueryResult<T>;
13+
/** What the loader requests be rendered when data is available */
14+
onSuccess: (data: T) => React.ReactElement;
15+
/** What the loader requests be rendered when the query fails */
16+
onError?: (
17+
error: SerializedError | FetchBaseQueryError
18+
) => JSX.Element;
19+
/** What the loader requests be rendered while loading data */
20+
onLoading?: React.ReactElement;
21+
/** What the loader requests be rendered while fetching data */
22+
onFetching?: React.ReactElement;
23+
/** What the loader requests be rendered while fetching data */
24+
whileFetching?: {
25+
/** Should be appended to the success result while fetching */
26+
append?: React.ReactElement;
27+
/** Should be prepended to the success result while fetching */
28+
prepend?: React.ReactElement;
29+
};
30+
};
31+
```
32+
33+
This is what the default `loaderComponent` looks like:
34+
35+
```typescript title=RTKLoader.tsx
36+
import { SerializedError } from "@reduxjs/toolkit";
37+
import * as React from "react";
38+
import { CustomLoaderProps } from "./types";
39+
40+
export function RTKLoader<T>(
41+
props: CustomLoaderProps<T>
42+
): React.ReactElement {
43+
const shouldLoad =
44+
props.query.isLoading || props.query.isUninitialized;
45+
const hasError = props.query.isError && props.query.error;
46+
const isFetching = props.query.isFetching;
47+
48+
if (shouldLoad) {
49+
return props.onLoading ?? <React.Fragment />;
50+
}
51+
52+
if (hasError) {
53+
return (
54+
props.onError?.(props.query.error as SerializedError) ?? (
55+
<React.Fragment />
56+
)
57+
);
58+
}
59+
60+
if (isFetching && props.onFetching) {
61+
return props.onFetching;
62+
}
63+
64+
if (props.query.data !== undefined) {
65+
const prepend = isFetching
66+
? props.whileFetching?.prepend ?? null
67+
: null;
68+
const append = isFetching
69+
? props.whileFetching?.append ?? null
70+
: null;
71+
const componentWithData = props.onSuccess(props.query.data);
72+
73+
return (
74+
<>
75+
{prepend}
76+
{componentWithData}
77+
{append}
78+
</>
79+
);
80+
}
81+
82+
return <React.Fragment />;
83+
}
84+
```
85+
786
You could pass a custom `loaderComponent` to your loaders, if you'd like:
887

988
```typescript

docs/docs/Features/index.md renamed to docs/docs/Features/index.mdx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,26 @@
22
sidebar_position: 5
33
---
44

5+
import DocCardList from "@theme/DocCardList";
6+
57
# Features
68

79
RTK Query Loader tries to give you all the flexibility you need to create reusable and extendable loaders.
810

9-
- Supply multiple queries.
11+
- Supply as many queries as you'd like.
1012
- Supply queries that [don't affect loading state](defer-queries.md).
11-
- [Transform](./transforming.md) the queries to your desired output-format.
13+
- Send down payloads that contain any static data.
14+
- [Transform](./transforming.md) the data to your desired output-format.
15+
- Set up [default](../Quick%20Guide/base-loader.md) loading and error states.
1216
- [Extend](./extending.md) existing loaders.
1317
- Re-use existing loaders
18+
- Create [stateful loaders](./stateful-loader)
1419

1520
And even if you don't use `RTK Query`...
1621

1722
- Supply queries that are [just promises](../Exports/use-create-query.md).
1823
- [Use with other data loading libraries](./other-libs.md)
24+
25+
---
26+
27+
<DocCardList />

docs/docs/Features/stateful-loader.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
---
2+
sidebar-position: 6
3+
---
4+
5+
# Stateful loaders
6+
7+
Since a `Loader` contains a hook, that hook can contain state.
8+
9+
```typescript
10+
const loader = createLoader({
11+
useQueries: () => {
12+
const [name, setName] = useState("charizard");
13+
const pokemon = useGetPokemon(name);
14+
return {
15+
queries: {
16+
pokemon,
17+
},
18+
};
19+
},
20+
});
21+
```
22+
23+
You can then control this state, by sending the handlers through `payload`:
24+
25+
```typescript {10}
26+
const componentLoader = createLoader({
27+
useQueries: () => {
28+
const [name, setName] = useState("charizard");
29+
const debouncedName = useDebounce(name, 200);
30+
const pokemon = useGetPokemon(debouncedName);
31+
return {
32+
queries: {
33+
pokemon,
34+
},
35+
payload: { name, setName },
36+
};
37+
},
38+
});
39+
40+
const Component = withLoader((props, loader) => {
41+
const onChange = (e) => loader.payload.setName(e.target.value);
42+
// ...
43+
}, componentLoader);
44+
```
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
---
2+
sidebar_position: 4
3+
---
4+
5+
# 4. Arguments for your loader
6+
7+
If you want the loader to take an argument, all you have to do is to add a `queriesArg`:
8+
9+
```tsx {5-7,10-12}
10+
import { ConsumerProps } from "@ryfylke-react/rtk-query-loader";
11+
12+
// This means that any component that has props that extend this
13+
// type can consume the loader using `withLoader`
14+
type UserRouteLoaderProps = ConsumerProps<{
15+
userId: string;
16+
}>;
17+
18+
export const userRouteLoader = baseLoader.extend({
19+
queriesArg: (props: UserRouteLoaderProps) => props.userId,
20+
// type is now inferred from queriesArg return
21+
useQueries: (userId) => {
22+
const user = useGetUserQuery(userId);
23+
const posts = useGetPostsByUser(userId);
24+
25+
return {
26+
queries: {
27+
user,
28+
posts,
29+
},
30+
};
31+
},
32+
});
33+
```
34+
35+
:::tip
36+
`ConsumerProps<T>` simply means that the consumer component's props should have _atleast_ the properties of `T`.
37+
38+
```typescript
39+
type ConsumerProps<T extends Record<string, unknown>> = Record<
40+
string,
41+
unknown
42+
> &
43+
T;
44+
```
45+
46+
:::
47+
48+
```typescript
49+
<UserRoute userId="1234" />
50+
// → queriesArg({ userId: "1234" })
51+
// → "1234"
52+
// → loader.useQueries("1234")
53+
```

docs/docs/Quick Guide/add-queries.md

Lines changed: 1 addition & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
sidebar_position: 3
33
---
44

5-
# Adding queries
5+
# 3. Add queries
66

77
You can now start to add queries to your extended loaders.
88

@@ -29,69 +29,3 @@ export const userRouteLoader = baseLoader.extend({
2929
```
3030

3131
You can add as many queries as you'd like to `Response.queries`, and they will all aggregate to a common loading state.
32-
33-
## Accepting arguments
34-
35-
If you want the loader to take an argument, you can do that.
36-
37-
```tsx {2}
38-
export const userRouteLoader = baseLoader.extend({
39-
useQueries: (userId: string) => {
40-
const user = useGetUserQuery(userId);
41-
const posts = useGetPostsByUser(userId);
42-
43-
return {
44-
queries: {
45-
user,
46-
posts,
47-
},
48-
};
49-
},
50-
});
51-
```
52-
53-
:::caution Beware
54-
If you want to consume this loader through `withLoader`, you need to add the `queriesArg` argument. This supplies the loader with an argument piped from `props`.
55-
:::
56-
57-
### `queriesArg`
58-
59-
This argument transforms the consumer's props to the queries argument.
60-
61-
```tsx {1-5,8-10}
62-
// This means that any component that has props that extend this
63-
// type can consume the loader using `withLoader`
64-
type UserRouteLoaderProps = Record<string, any> & {
65-
userId: string;
66-
};
67-
68-
export const userRouteLoader = baseLoader.extend({
69-
queriesArg: (props: UserRouteLoaderProps) => props.userId,
70-
// type is now inferred from queriesArg return
71-
useQueries: (userId) => {
72-
const user = useGetUserQuery(userId);
73-
const posts = useGetPostsByUser(userId);
74-
75-
return {
76-
queries: {
77-
user,
78-
posts,
79-
},
80-
};
81-
},
82-
});
83-
```
84-
85-
A component consuming this loader would pass the argument automatically through this pipeline:
86-
87-
```typescript
88-
// props → queriesArg → useQueries
89-
loaderArgs.useQueries(queriesArg(consumerProps));
90-
```
91-
92-
```typescript
93-
<UserRoute userId="1234" />
94-
// → queriesArg({ userId: "1234" })
95-
// → "1234"
96-
// → loader.useQueries("1234")
97-
```

0 commit comments

Comments
 (0)