Skip to content

Commit 3073119

Browse files
authoredMar 30, 2022
Merge pull request #7444 from marmelab/fix-list-redirect-v3
[v3] Fix race condition due to debounced setFilter
2 parents 81c2c7e + ca0c687 commit 3073119

File tree

3 files changed

+23
-0
lines changed

3 files changed

+23
-0
lines changed
 

‎cypress/integration/list.js

+6
Original file line numberDiff line numberDiff line change
@@ -102,13 +102,19 @@ describe('List Page', () => {
102102
LoginPage.login('admin', 'password');
103103
ListPagePosts.navigate();
104104
ListPagePosts.showFilter('title');
105+
// Let's clear the filter first, otherwise we have no way of knowing when the new filter has been (debounced and) applied
106+
ListPagePosts.setFilterValue('title', '');
107+
cy.contains('1-10 of 13');
108+
// Now let's change the filter to something different than the default value
105109
ListPagePosts.setFilterValue(
106110
'title',
107111
'Omnis voluptate enim similique est possimus'
108112
);
109113
cy.contains('1-1 of 1');
114+
// Navigate away and then back
110115
cy.get('[href="#/users"]').click();
111116
cy.get('[href="#/posts"]').click();
117+
// Check that our filter has been preserved
112118
cy.get(ListPagePosts.elements.filter('title')).should(el =>
113119
expect(el).to.have.value(
114120
'Omnis voluptate enim similique est possimus'

‎packages/ra-core/src/controller/useListParams.ts

+7
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import queryReducer, {
1717
import { changeListParams, ListParams } from '../actions/listActions';
1818
import { SortPayload, ReduxState, FilterPayload } from '../types';
1919
import removeEmpty from '../util/removeEmpty';
20+
import { useIsMounted } from '../util/hooks';
2021

2122
interface ListParamsOptions {
2223
resource: string;
@@ -126,6 +127,7 @@ const useListParams = ({
126127
shallowEqual
127128
);
128129
const tempParams = useRef<ListParams>();
130+
const isMounted = useIsMounted();
129131

130132
const requestSignature = [
131133
location.search,
@@ -164,6 +166,11 @@ const useListParams = ({
164166
}, [location.search]); // eslint-disable-line
165167

166168
const changeParams = useCallback(action => {
169+
// do not change params if the component is already unmounted
170+
// this is necessary because changeParams can be debounced, and therefore
171+
// executed after the component is unmounted
172+
if (!isMounted.current) return;
173+
167174
if (!tempParams.current) {
168175
// no other changeParams action dispatched this tick
169176
tempParams.current = queryReducer(query, action);

‎packages/ra-core/src/util/hooks.ts

+10
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,13 @@ export function useTimeout(ms = 0) {
6262

6363
return ready;
6464
}
65+
66+
export function useIsMounted() {
67+
const isMounted = useRef(true);
68+
useEffect(() => {
69+
return () => {
70+
isMounted.current = false;
71+
};
72+
}, []);
73+
return isMounted;
74+
}

0 commit comments

Comments
 (0)
Please sign in to comment.