@@ -105,11 +105,12 @@ render(<UsersPage />);
105
105
``` ts title="resources/User" collapsed
106
106
export class User extends Entity {
107
107
id = 0 ;
108
+ username = ' ' ;
108
109
name = ' ' ;
109
110
email = ' ' ;
110
111
website = ' ' ;
111
112
pk() {
112
- return ` ${ this .id } ` ;
113
+ return this .id ;
113
114
}
114
115
}
115
116
export const UserResource = resource ({
@@ -124,15 +125,19 @@ import { User } from './User';
124
125
125
126
export class Todo extends Entity {
126
127
id = 0 ;
127
- userId = User .fromJS ({});
128
+ userId = 0 ;
129
+ user? = User .fromJS ({});
128
130
title = ' ' ;
129
131
completed = false ;
130
132
pk() {
131
- return ` ${ this .id } ` ;
133
+ return this .id ;
132
134
}
133
135
static schema = {
134
- userId : User ,
136
+ user : User ,
135
137
};
138
+ static process(input ) {
139
+ return { ... input , user: input .userId };
140
+ }
136
141
}
137
142
export const TodoResource = resource ({
138
143
urlPrefix: ' https://jsonplaceholder.typicode.com' ,
@@ -142,17 +147,49 @@ export const TodoResource = resource({
142
147
});
143
148
```
144
149
150
+ ``` tsx title="TodoByUser" collapsed
151
+ import { useQuery } from ' @data-client/react' ;
152
+ import { User } from ' ./resources/User' ;
153
+ import type { Todo } from ' ./resources/Todo' ;
154
+
155
+ export default function TodoByUser({ userId , todos }: Props ) {
156
+ const user = useQuery (User , { id: userId });
157
+ // don't bother if no user is loaded yet
158
+ if (! user ) return null ;
159
+ return (
160
+ <div >
161
+ <h3 >
162
+ { user .name } has { tasksRemaining (todos )} tasks left
163
+ </h3 >
164
+ { todos .slice (0 , 3 ).map (todo => (
165
+ <div key = { todo .pk ()} >
166
+ { todo .title } by { todo .user === user ? todo .user .name : ' ' }
167
+ </div >
168
+ ))}
169
+ </div >
170
+ );
171
+ }
172
+ function tasksRemaining(todos : Todo []) {
173
+ return todos .filter (({ completed }) => ! completed ).length ;
174
+ }
175
+ interface Props {
176
+ userId: string ;
177
+ todos: Todo [];
178
+ }
179
+ ```
180
+
145
181
``` tsx title="TodoJoined"
146
182
import { schema } from ' @data-client/rest' ;
147
183
import { useQuery , useFetch } from ' @data-client/react' ;
148
184
import { TodoResource , Todo } from ' ./resources/Todo' ;
149
185
import { UserResource } from ' ./resources/User' ;
186
+ import TodoByUser from ' ./TodoByUser' ;
150
187
151
188
const groupTodoByUser = new schema .Query (
152
189
TodoResource .getList .schema ,
153
190
todos => {
154
- return Object .groupBy (todos , todo => todo ? .userId ?. username ) as Record <
155
- string ,
191
+ return Object .groupBy (todos , todo => todo .userId ) as Record <
192
+ number ,
156
193
Todo []
157
194
>;
158
195
},
@@ -162,30 +199,21 @@ function TodosPage() {
162
199
useFetch (UserResource .getList );
163
200
useSuspense (TodoResource .getList );
164
201
useSuspense (UserResource .getList );
165
- const todoByUser = useQuery (groupTodoByUser );
166
- if (! todoByUser ) return <div >Todos not found</div >;
202
+ const todosByUser = useQuery (groupTodoByUser );
203
+ if (! todosByUser ) return <div >Todos not found</div >;
167
204
return (
168
205
<div >
169
- { Object .keys (todoByUser ).map (username => (
170
- <div key = { username } >
171
- <h3 >
172
- { username } has { tasksRemaining (todoByUser [username ])} tasks
173
- left
174
- </h3 >
175
- { todoByUser [username ].slice (0 , 3 ).map (todo => (
176
- <div key = { todo .pk ()} >
177
- { todo .title } by { todo ?.userId ?.name }
178
- </div >
179
- ))}
180
- </div >
206
+ { Object .keys (todosByUser ).map (userId => (
207
+ <TodoByUser
208
+ key = { userId }
209
+ userId = { userId }
210
+ todos = { todosByUser [userId ]}
211
+ />
181
212
))}
182
213
</div >
183
214
);
184
215
}
185
216
186
- function tasksRemaining(todos : Todo []) {
187
- return todos .filter (({ completed }) => ! completed ).length ;
188
- }
189
217
render (<TodosPage />);
190
218
```
191
219
0 commit comments