-
-
Notifications
You must be signed in to change notification settings - Fork 5.3k
/
Copy pathuseGetList.ts
134 lines (126 loc) · 3.99 KB
/
useGetList.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import { useMemo } from 'react';
import get from 'lodash/get';
import {
PaginationPayload,
SortPayload,
ReduxState,
Identifier,
Record,
RecordMap,
} from '../types';
import useQueryWithStore from './useQueryWithStore';
const defaultIds = [];
const defaultData = {};
/**
* Call the dataProvider.getList() method and return the resolved result
* as well as the loading state.
*
* The return value updates according to the request state:
*
* - start: { loading: true, loaded: false }
* - success: { data: [data from store], ids: [ids from response], total: [total from response], loading: false, loaded: true }
* - error: { error: [error from response], loading: false, loaded: true }
*
* This hook will return the cached result when called a second time
* with the same parameters, until the response arrives.
*
* @param {string} resource The resource name, e.g. 'posts'
* @param {Object} pagination The request pagination { page, perPage }, e.g. { page: 1, perPage: 10 }
* @param {Object} sort The request sort { field, order }, e.g. { field: 'id', order: 'DESC' }
* @param {Object} filter The request filters, e.g. { title: 'hello, world' }
* @param {Object} options Options object to pass to the dataProvider. May include side effects to be executed upon success or failure, e.g. { onSuccess: { refresh: true } }
*
* @returns The current request state. Destructure as { data, total, ids, error, loading, loaded }.
*
* @example
*
* import { useGetList } from 'react-admin';
*
* const LatestNews = () => {
* const { data, ids, loading, error } = useGetList(
* 'posts',
* { page: 1, perPage: 10 },
* { field: 'published_at', order: 'DESC' }
* );
* if (loading) { return <Loading />; }
* if (error) { return <p>ERROR</p>; }
* return <ul>{ids.map(id =>
* <li key={id}>{data[id].title}</li>
* )}</ul>;
* };
*/
const useGetList = <RecordType extends Record = Record>(
resource: string,
pagination: PaginationPayload,
sort: SortPayload,
filter: object,
options?: any
): {
data?: RecordMap<RecordType>;
ids?: Identifier[];
total?: number;
error?: any;
loading: boolean;
loaded: boolean;
} => {
const requestSignature = JSON.stringify({ pagination, sort, filter });
const {
data: { ids, allRecords },
total,
error,
loading,
loaded,
} = useQueryWithStore(
{ type: 'getList', resource, payload: { pagination, sort, filter } },
options,
// ids and data selector
(state: ReduxState): DataSelectorResult<RecordType> => ({
ids: get(
state.admin.resources,
[resource, 'list', 'cachedRequests', requestSignature, 'ids'],
null
),
allRecords: get(
state.admin.resources,
[resource, 'data'],
defaultData
),
}),
// total selector (may return undefined)
(state: ReduxState): number =>
get(state.admin.resources, [
resource,
'list',
'cachedRequests',
requestSignature,
'total',
]),
(data: DataSelectorResult<RecordType>) => data.ids !== null
);
const data = useMemo(
() =>
ids === null
? defaultData
: ids
.map(id => allRecords[id])
.reduce((acc, record) => {
if (!record) return acc;
acc[record.id] = record;
return acc;
}, {}),
[ids, allRecords]
);
return {
data,
ids: ids === null ? defaultIds : ids,
total,
error,
loading,
loaded,
};
};
interface DataSelectorResult<RecordType extends Record = Record> {
ids: Identifier[];
allRecords: RecordMap<RecordType>;
}
export default useGetList;