@@ -28,22 +28,6 @@ which guarantees data like [await](https://developer.mozilla.org/en-US/docs/Web/
28
28
``` ts title="Resources" collapsed
29
29
import { Entity , createResource } from ' @data-client/rest' ;
30
30
31
- export class Post extends Entity {
32
- id = 0 ;
33
- userId = 0 ;
34
- title = ' ' ;
35
- body = ' ' ;
36
-
37
- pk() {
38
- return this .id ?.toString ();
39
- }
40
- static key = ' Post' ;
41
- }
42
- export const PostResource = createResource ({
43
- path: ' /posts/:id' ,
44
- schema: Post ,
45
- });
46
-
47
31
export class User extends Entity {
48
32
id = 0 ;
49
33
name = ' ' ;
@@ -57,7 +41,7 @@ export class User extends Entity {
57
41
}
58
42
59
43
pk() {
60
- return ` ${ this .id } ` ;
44
+ return this .id ;
61
45
}
62
46
static key = ' User' ;
63
47
}
@@ -66,22 +50,42 @@ export const UserResource = createResource({
66
50
path: ' /users/:id' ,
67
51
schema: User ,
68
52
});
53
+
54
+ export class Post extends Entity {
55
+ id = 0 ;
56
+ author = User .fromJS ();
57
+ title = ' ' ;
58
+ body = ' ' ;
59
+
60
+ pk() {
61
+ return this .id ;
62
+ }
63
+ static key = ' Post' ;
64
+
65
+ static schema = {
66
+ author: User ,
67
+ };
68
+ }
69
+ export const PostResource = createResource ({
70
+ path: ' /posts/:id' ,
71
+ schema: Post ,
72
+ paginationField: ' page' ,
73
+ });
69
74
```
70
75
71
- ``` tsx title="PostDetail" {5-6 } collapsed
76
+ ``` tsx title="PostDetail" {5} collapsed
72
77
import { useSuspense } from ' @data-client/react' ;
73
- import { UserResource , PostResource } from ' ./Resources' ;
78
+ import { PostResource } from ' ./Resources' ;
74
79
75
80
export default function PostDetail({ setRoute , id }) {
76
81
const post = useSuspense (PostResource .get , { id });
77
- const author = useSuspense (UserResource .get , { id: post .userId });
78
82
return (
79
83
<div >
80
84
<header >
81
85
<div className = " listItem spaced" >
82
86
<div className = " author" >
83
- <Avatar src = { author .profileImage } />
84
- <small >{ author .name } </small >
87
+ <Avatar src = { post . author .profileImage } />
88
+ <small >{ post . author .name } </small >
85
89
</div >
86
90
<h4 >{ post .title } </h4 >
87
91
</div >
@@ -101,15 +105,13 @@ export default function PostDetail({ setRoute, id }) {
101
105
}
102
106
```
103
107
104
- ``` tsx title="PostItem" {5} collapsed
105
- import { useSuspense } from ' @data-client/react' ;
106
- import { UserResource , type Post } from ' ./Resources' ;
108
+ ``` tsx title="PostItem" collapsed
109
+ import { type Post } from ' ./Resources' ;
107
110
108
111
export default function PostItem({ post , setRoute }: Props ) {
109
- const author = useSuspense (UserResource .get , { id: post .userId });
110
112
return (
111
113
<div className = " listItem spaced" >
112
- <Avatar src = { author .profileImage } />
114
+ <Avatar src = { post . author .profileImage } />
113
115
<div >
114
116
<h4 >
115
117
<a
@@ -122,7 +124,7 @@ export default function PostItem({ post, setRoute }: Props) {
122
124
{ post .title }
123
125
</a >
124
126
</h4 >
125
- <small >by { author .name } </small >
127
+ <small >by { post . author .name } </small >
126
128
</div >
127
129
</div >
128
130
);
@@ -152,6 +154,8 @@ export default function PostList({ setRoute }) {
152
154
```
153
155
154
156
``` tsx title="Navigation" collapsed
157
+ import { useController , useLoading } from ' @data-client/react' ;
158
+ import { PostResource } from ' ./Resources' ;
155
159
import PostList from ' ./PostList' ;
156
160
import PostDetail from ' ./PostDetail' ;
157
161
@@ -160,7 +164,21 @@ function Navigation() {
160
164
if (route .startsWith (' detail' ))
161
165
return <PostDetail setRoute = { setRoute } id = { route .split (' /' )[1 ]} />;
162
166
163
- return <PostList setRoute = { setRoute } />;
167
+ return <><PostList setRoute = { setRoute } /><LoadMore /></>;
168
+ }
169
+
170
+ function LoadMore() {
171
+ const ctrl = useController ();
172
+ const posts = useQuery (PostResource .getList .schema );
173
+ const [nextPage, isPending] = useLoading (
174
+ () => ctrl .fetch (PostResource .getList .getPage , { page: 2 }),
175
+ );
176
+ if (posts ?.length % 3 !== 0 ) return null ;
177
+ return (
178
+ <center >
179
+ <button onClick = { nextPage } >{ isPending ? " ..." : ' Load more' } </button >
180
+ </center >
181
+ )
164
182
}
165
183
render (<Navigation />);
166
184
```
0 commit comments