Skip to content

Commit 839fd76

Browse files
committed
feat: New config property, better InferLoaderData,
1 parent 02a7b98 commit 839fd76

File tree

12 files changed

+481
-152
lines changed

12 files changed

+481
-152
lines changed

docs/docs/Features/defer-queries.md

+18-3
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,22 @@ const loader = createLoader({
3030
});
3131
```
3232

33-
Deferred queries
33+
## Configure
3434

35-
- Do not affect the loading state
36-
- Cause the component to rerender when fulfilled
35+
> **New in version 1.0.3**
36+
37+
You can pass a `Config` to your `Loader`s:
38+
39+
```typescript {4-8}
40+
const loader = createLoader({
41+
useQueries: () => ({...}),
42+
onError: () => (...),
43+
config: {
44+
deferred: {
45+
shouldThrowError: true,
46+
},
47+
}
48+
})
49+
```
50+
51+
- `shouldThrowError` - Determines whether or not `deferredQueries` should send the component to the `onError` view if one of the deferred queries end up in a error state.

docs/docs/Quick Guide/index.mdx

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@ import DocCardList from "@theme/DocCardList";
66

77
# Quick guide
88

9-
`rtk-query-loader` is a tool that you can use to clean up your codebase and prevent duplicate code. The following guide will walk you through some of our recommended best practises for making the most out of this package.
9+
The following guide will walk you through some of our recommended best practises for making the most out of RTK Query Loader.
1010

1111
<DocCardList />

docs/docs/examples.md

-47
This file was deleted.

docs/docs/examples.mdx

+152
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
---
2+
sidebar_position: 3
3+
---
4+
5+
import TOCInline from "@theme/TOCInline";
6+
7+
# Examples
8+
9+
This page contains a collection of examples that cover typical use cases for the library.
10+
11+
<TOCInline toc={toc} />
12+
13+
## React Router (route loader)
14+
15+
By utilizing `useParams` from `react-router-dom` we can create a loader that will load data based on the route parameters.
16+
17+
```tsx
18+
import {
19+
withLoader,
20+
createLoader,
21+
} from "@ryfylke-react/rtk-query-loader";
22+
import { useParams, Redirect } from "react-router-dom";
23+
// ...
24+
25+
const userRouteLoader = createLoader({
26+
useQueries: () => {
27+
const { userId } = useParams();
28+
const userQuery = useGetUserQuery(userId, {
29+
skip: userId ? false : true,
30+
});
31+
32+
return {
33+
queries: {
34+
userQuery,
35+
},
36+
};
37+
},
38+
onLoading: (props) => {
39+
const { userId } = useParams();
40+
if (!userId) {
41+
return <Redirect to="/users" />;
42+
}
43+
return <PageSkeleton />;
44+
},
45+
onError: (props, error) => <ErrorView error={error} />,
46+
});
47+
```
48+
49+
## Reusable loader
50+
51+
We can also create a reusable loader that can be used with multiple components.
52+
53+
```tsx
54+
import {
55+
withLoader,
56+
createLoader,
57+
ConsumerProps,
58+
} from "@ryfylke-react/rtk-query-loader";
59+
60+
type UserLoaderProps = {
61+
userId: string;
62+
};
63+
64+
const userLoader = createLoader<UserLoaderProps>({
65+
queriesArg: (props: UserLoaderProps) => props.userId,
66+
useQueries: (userId) => {
67+
const userQuery = useGetUserQuery(userId);
68+
69+
return {
70+
queries: {
71+
userQuery,
72+
},
73+
};
74+
},
75+
onLoading: (props) => <PageSkeleton />,
76+
onError: (props, error) => <ErrorView error={error} />,
77+
});
78+
```
79+
80+
You can now use the `userLoader` in any component whos props extend `UserLoaderProps`.
81+
82+
### Consumer 1
83+
84+
```tsx title="UserProfile.tsx"
85+
import { userLoader } from "../loaders";
86+
87+
type UserProfileProps = {
88+
userId: string;
89+
// ... other props
90+
};
91+
92+
export const UserProfile = withLoader(
93+
(props: UserProfileProps, data) => {
94+
return <>...</>;
95+
},
96+
userLoader
97+
);
98+
```
99+
100+
### Consumer 2
101+
102+
```tsx title="UserProfile.tsx"
103+
import { userLoader } from "../loaders";
104+
105+
type InlineUserDetailsProps = {
106+
userId: string;
107+
dir: "row" | "column";
108+
// ... other props
109+
};
110+
111+
export const InlineUserDetails = withLoader(
112+
(props: InlineUserDetailsProps, data) => {
113+
return <>...</>;
114+
},
115+
userLoader
116+
);
117+
```
118+
119+
## Stateful loader
120+
121+
You can also create loaders that contain state.
122+
123+
```tsx
124+
const loader = createLoader({
125+
useQueries: () => {
126+
const [name, setName] = useState("charizard");
127+
const debouncedName = useDebounce(name, 200);
128+
const pokemon = useGetPokemon(debouncedName);
129+
return {
130+
queries: {
131+
pokemon,
132+
},
133+
payload: {
134+
name,
135+
setName,
136+
},
137+
};
138+
},
139+
});
140+
141+
const Consumer = withLoader((props, data) => {
142+
return (
143+
<div>
144+
<input
145+
value={data.payload.name}
146+
onChange={(e) => data.payload.setName(e.target.value)}
147+
/>
148+
<div>AP: {data.queries.pokemon.data.ability_power}</div>
149+
</div>
150+
);
151+
}, loader);
152+
```

docs/docs/intro.md

+17-11
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,27 @@ slug: /
55

66
# RTK Query Loader
77

8-
Lets you create loaders for use with [RTK Query](https://redux-toolkit.js.org/rtk-query/overview).
8+
> Create _loaders_ for your React components.
99
10-
- [x] **Reusable**
11-
- [x] **Extendable**
12-
- [x] **Transformable**
13-
- [x] **Type-safe**
10+
🔗 **Extendable**
11+
💫 **Transformable**
12+
♻️ **Reusable**
13+
**Properly typed**
14+
15+
You write your components, as if the data has already loaded.
16+
17+
## Install
1418

1519
```shell
1620
npm i @ryfylke-react/rtk-query-loader
1721
```
1822

19-
:::caution These docs are for version 1.0.0 and up
20-
If you are using version `0.3.51` or earlier, please refer to the [**migration guide**](./Migrations/v0.x).
21-
:::
23+
## Playground
2224

23-
:::tip Getting Started
24-
Get started with our recommended best practises by following the [**Quick guide**](/Quick%20guide), or looking at a [simple example](./examples.md).
25-
:::
25+
<iframe
26+
src="https://codesandbox.io/embed/ryfylke-react-rtk-query-loader-demo-du3936?codemirror=1&fontsize=14&hidenavigation=1&module=%2Fsrc%2Fpokemon%2FPokemon.tsx&theme=dark"
27+
style={{width: "100%", height: 600, marginBottom: "1rem"}}
28+
title="@ryfylke-react/rtk-query-loader Demo"
29+
allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking"
30+
sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
31+
></iframe>

docs/docs/problem-solve.md

+14-40
Original file line numberDiff line numberDiff line change
@@ -4,43 +4,17 @@ sidebar_position: 2
44

55
# What problem does this solve?
66

7-
Handling the loading and error state of components that depend on external data can be tedious,
8-
especially when there are multiple queries. It is also usually solved inconsistently throughout the project. Your options are essentially
9-
10-
1. Return early (and show loading state)
11-
2. Deal with it in the JSX using conditional rendering, optional chaining, etc...
12-
13-
If you are going for `2`, then you will also have to deal with the type being `T | undefined` in your component methods, which is a bummer.
14-
15-
```tsx
16-
function Component(props){
17-
const userQuery = useGetUser(props.id);
18-
const postsQuery = userGetPostsByUser(userQuery.data?.id, {
19-
skip: user?.data?.id === undefined,
20-
});
21-
22-
if (userQuery.isError || postsQuery.isError){
23-
// handle error
24-
}
25-
26-
/* possible something like */
27-
// if (userQuery.isLoading){ return (...) }
28-
29-
return (
30-
<div>
31-
{/* or checking if the type is undefined in the jsx */}
32-
{(userQuery.isLoading || postsQuery.isLoading) && (...)}
33-
{userQuery.data && postsQuery.data && (...)}
34-
</div>
35-
)
36-
}
37-
```
38-
39-
What if we could instead "join" these queries into one, and then just return early if we are in the initial loading stage. That's basically the approach that rtk-query-loader takes. Some pros include:
40-
41-
- [x] You get to isolate the data-loading code away from the presentational components
42-
- [x] Better type certainty
43-
- [x] Way less optional chaining in your components
44-
- [x] Reusability across multiple components
45-
- [x] Extendability
46-
- [x] Transform the output to any format you'd like.
7+
Handling the loading and error state of components that depend on external data can be very tedious,
8+
especially when you are managing multiple queries. RTK Query Loader aims to help you solve these issues by letting you create composable loaders that you can move out of the presentational components.
9+
10+
- [x] Isolate the data-loading code away from the presentational components
11+
- [x] Increased type certainty
12+
- 🔥 Way less optional chaining in your components
13+
- 🔥 You write the components as if the data is already present
14+
- [x] Composability
15+
- ♻️ Extend existing loaders
16+
- ♻️ Overwrite only select properties
17+
- [x] Full control
18+
- 🛠️ Loading/error states
19+
- 🛠️ Custom loader-component
20+
- 🛠️ Control defer behaviour

docs/package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@
1919
"@docusaurus/preset-classic": "2.3.1",
2020
"@docusaurus/theme-search-algolia": "^2.3.1",
2121
"@mdx-js/react": "^1.6.22",
22+
"@reduxjs/toolkit": "^1.9.3",
2223
"clsx": "^1.2.1",
2324
"prism-react-renderer": "^1.3.5",
2425
"react": "^17.0.2",
25-
"react-dom": "^17.0.2"
26+
"react-dom": "^17.0.2",
27+
"react-redux": "^8.0.5"
2628
},
2729
"devDependencies": {
2830
"@docusaurus/module-type-aliases": "2.3.1",

0 commit comments

Comments
 (0)