Skip to content

Commit e2c4935

Browse files
authoredNov 30, 2020
Merge pull request #5577 from marmelab/Fix-logout-causes-error-in-useGetList
Fix logout causes error in useGetList
2 parents 8646bab + d05c466 commit e2c4935

File tree

2 files changed

+62
-40
lines changed

2 files changed

+62
-40
lines changed
 

‎packages/ra-core/src/dataProvider/useGetList.ts

+47-23
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useSelector, shallowEqual } from 'react-redux';
1+
import { useMemo } from 'react';
22
import get from 'lodash/get';
33

44
import {
@@ -11,6 +11,7 @@ import {
1111
} from '../types';
1212
import useQueryWithStore from './useQueryWithStore';
1313

14+
const defaultIds = [];
1415
const defaultData = {};
1516

1617
/**
@@ -67,16 +68,28 @@ const useGetList = <RecordType extends Record = Record>(
6768
} => {
6869
const requestSignature = JSON.stringify({ pagination, sort, filter });
6970

70-
const { data: ids, total, error, loading, loaded } = useQueryWithStore(
71+
const {
72+
data: { ids, allRecords },
73+
total,
74+
error,
75+
loading,
76+
loaded,
77+
} = useQueryWithStore(
7178
{ type: 'getList', resource, payload: { pagination, sort, filter } },
7279
options,
73-
// data selector (may return [])
74-
(state: ReduxState): Identifier[] =>
75-
get(
80+
// ids and data selector
81+
(state: ReduxState): DataSelectorResult<RecordType> => ({
82+
ids: get(
7683
state.admin.resources,
7784
[resource, 'list', 'cachedRequests', requestSignature, 'ids'],
78-
[]
85+
null
7986
),
87+
allRecords: get(
88+
state.admin.resources,
89+
[resource, 'data'],
90+
defaultData
91+
),
92+
}),
8093
// total selector (may return undefined)
8194
(state: ReduxState): number =>
8295
get(state.admin.resources, [
@@ -85,26 +98,37 @@ const useGetList = <RecordType extends Record = Record>(
8598
'cachedRequests',
8699
requestSignature,
87100
'total',
88-
])
101+
]),
102+
(data: DataSelectorResult<RecordType>) => data.ids !== null
89103
);
90104

91-
const data = useSelector((state: ReduxState): RecordMap<RecordType> => {
92-
if (!ids) return defaultData;
93-
const allResourceData = get(
94-
state.admin.resources,
95-
[resource, 'data'],
96-
defaultData
97-
);
98-
return ids
99-
.map(id => allResourceData[id])
100-
.reduce((acc, record) => {
101-
if (!record) return acc;
102-
acc[record.id] = record;
103-
return acc;
104-
}, {});
105-
}, shallowEqual);
105+
const data = useMemo(
106+
() =>
107+
ids === null
108+
? defaultData
109+
: ids
110+
.map(id => allRecords[id])
111+
.reduce((acc, record) => {
112+
if (!record) return acc;
113+
acc[record.id] = record;
114+
return acc;
115+
}, {}),
116+
[ids, allRecords]
117+
);
106118

107-
return { data, ids, total, error, loading, loaded };
119+
return {
120+
data,
121+
ids: ids === null ? defaultIds : ids,
122+
total,
123+
error,
124+
loading,
125+
loaded,
126+
};
108127
};
109128

129+
interface DataSelectorResult<RecordType extends Record = Record> {
130+
ids: Identifier[];
131+
allRecords: RecordMap<RecordType>;
132+
}
133+
110134
export default useGetList;

‎packages/ra-core/src/dataProvider/useQueryWithStore.ts

+15-17
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,6 @@ export type PartialQueryState = {
3737

3838
const queriesThisTick: { [key: string]: Promise<PartialQueryState> } = {};
3939

40-
/**
41-
* Lists of records are initialized to a particular object,
42-
* so detecting if the list is empty requires some work.
43-
*
44-
* @see src/reducer/admin/data.ts
45-
*/
46-
const isEmptyList = data =>
47-
Array.isArray(data)
48-
? data.length === 0
49-
: data &&
50-
Object.keys(data).length === 0 &&
51-
data.hasOwnProperty('fetchedAt');
52-
5340
/**
5441
* Default cache selector. Allows to cache responses by default.
5542
*
@@ -72,6 +59,8 @@ const defaultTotalSelector = query => (state: ReduxState) => {
7259
: null;
7360
};
7461

62+
const defaultIsDataLoaded = (data: any): boolean => data !== undefined;
63+
7564
/**
7665
* Fetch the data provider through Redux, return the value from the store.
7766
*
@@ -120,7 +109,8 @@ const useQueryWithStore = <State extends ReduxState = ReduxState>(
120109
query: Query,
121110
options: QueryOptions = { action: 'CUSTOM_QUERY' },
122111
dataSelector: (state: State) => any = defaultDataSelector(query),
123-
totalSelector: (state: State) => number = defaultTotalSelector(query)
112+
totalSelector: (state: State) => number = defaultTotalSelector(query),
113+
isDataLoaded: (data: any) => boolean = defaultIsDataLoaded
124114
): {
125115
data?: any;
126116
total?: number;
@@ -142,7 +132,7 @@ const useQueryWithStore = <State extends ReduxState = ReduxState>(
142132
total,
143133
error: null,
144134
loading: true,
145-
loaded: data !== undefined && !isEmptyList(data),
135+
loaded: isDataLoaded(data),
146136
});
147137

148138
useEffect(() => {
@@ -154,7 +144,7 @@ const useQueryWithStore = <State extends ReduxState = ReduxState>(
154144
total,
155145
error: null,
156146
loading: true,
157-
loaded: data !== undefined && !isEmptyList(data),
147+
loaded: isDataLoaded(data),
158148
});
159149
} else if (!isEqual(state.data, data) || state.total !== total) {
160150
// the dataProvider response arrived in the Redux store
@@ -171,7 +161,15 @@ const useQueryWithStore = <State extends ReduxState = ReduxState>(
171161
}));
172162
}
173163
}
174-
}, [data, requestSignature, setState, state.data, state.total, total]);
164+
}, [
165+
data,
166+
requestSignature,
167+
setState,
168+
state.data,
169+
state.total,
170+
total,
171+
isDataLoaded,
172+
]);
175173

176174
const dataProvider = useDataProvider();
177175
useEffect(() => {

0 commit comments

Comments
 (0)
Please sign in to comment.