问题
Assume I have a route /customers where a List of customers is being rendered. On that same route there's also a side drawer present. That drawer contains a List with a Filter of help topics.
When I start typing in the Filter in the side drawer, the url changes. That's according to how react-admin's list filter is working.
The problem is that the customers list is noticing the route changes. In effect it starts querying and reloading customers based on a search term that is related to help topics. No customers found of course.
I want the customer list to not notice I'm filtering on help topics. The solution I'm aiming for is that the list filter in the side drawer will not change the url while I input a help topic search term.
How can I configure or customise the filter in the side drawer to not change the url while typing, but store the current filter value in something like component state instead?
Actually, since the filter lives in a form (by react-final-form), which keeps its own state, I could live with a solution like this. But of course publishToUrl
isn't an available prop for Filter.
const MyFilter = props => (
<Filter {...props} publishToUrl={false} >
<TextInput source="title" />
</Filter>
);
Related:
- https://github.com/marmelab/react-admin/issues/2519
- https://github.com/marmelab/react-admin/issues/3521
回答1:
setFilters() property is passed down to Filter component from his parent List.
So you need to implement your own useListParams hook with removed/wrapped with condition commented lines:
const changeParams = useCallback(action => {
const newQuery = getQuery({
location,
params,
filterDefaultValues,
sort,
perPage,
});
const newParams = queryReducer(newQuery, action);
// history.push({
// search: `?${stringify({
// ...newParams,
// filter: JSON.stringify(newParams.filter),
// })}`,
// });
dispatch(changeListParams(resource, newParams));
}, requestSignature); // eslint-disable-line react-hooks/exhaustive-deps
Then you have to implement useListController and call your hook instead of react-admin's one.
const [query, queryModifiers] = useListParams({
resource,
location,
filterDefaultValues,
sort,
perPage,
debounce,
});
Finally you implement List component and pass your new cool useListController. Filter values will not be reflected in query string as well as paging and sorting.
Another and simpler way is to intercept setFilters call in your Filter component and do
dispatch(changeListParams(resource, newParams));
with new filter values without implementation bunch of hooks and components.
回答2:
Thanks to the directions provided by d0berm4n, I was able to compile a working solution (for react-admin 3.x). It's pretty limited in terms of the query that it creates (just filter), but it's just wat I need.
import React, { useCallback } from 'react';
import PropTypes from 'prop-types';
import { useDispatch } from 'react-redux';
import lodashDebounce from 'lodash/debounce';
import { Filter, TextInput, changeListParams } from 'react-admin';
const MyFilter = ({ resource, ...rest }) => {
const dispatch = useDispatch();
const debouncedSetFilters = lodashDebounce((filter = {}) => {
const query = { filter };
dispatch(changeListParams(resource, query));
}, 500);
const setFilters = useCallback(debouncedSetFilters, []);
return (
<Filter resource={resource} {...rest} setFilters={setFilters}>
<TextInput source="title" alwaysOn resettable />
</Filter>
);
};
MyFilter.propTypes = {
resource: PropTypes.string,
};
MyFilter.displayName = 'MyFilter';
export default MyFilter;
Update: This solution is incomplete. Other filters on the same page are now starting to query on the List that MyFilter is on. I suspect that's a problem that I can isolate. More on this later...
回答3:
I have tried a different solution, perhaps it will be of help to someone:
const FunctionsFilter = ({resource, ...rest}) => {
const classes = useStyles();
const location = useLocation();
const [query, queryModifiers] = useMyListParams({
resource,
location,
filterDefaultValues: {},
sort: {
field: 'name',
order: 'asc',
},
perPage: 5,
debounce: 500,
});
return (
<Filter resource={resource} {...rest} setFilters={queryModifiers.setFilters}>
<TextInput className={classes.dialogformfilter} source="name" alwaysOn resettable/>
</Filter>
);
};
Now, for some reason it sends the query twice, so i also copied useListController to useMyListController, and now it only sends it once. The downside is that you have to maintain it on version upgrades.
Also, a combination of Christiaan Westerbeek solution with useMyListController, worked best for me.
回答4:
I had similar issue. I have one route with three tabs. On each tab I have different List rendered. Once I had selected filters on tab1, they were propagated to url and applied to tab2 list and tab3 list.
I found solution to this:
I've analyzed react-admin source code. It is using method "changeParams" in useListParams.ts. This method is using useHistory();
from 'react-router-dom', and pushes filter params to url:
history.push({
search: `?${stringify({
...newParams,
filter: JSON.stringify(newParams.filter),
displayedFilters: JSON.stringify(newParams.displayedFilters),
})}`,
});
So my solution is that on tabs change I did history.push({ search: '' });
(of course you have to first install react-router-dom, import useHistory, and then make history as a const const history = useHistory();
).
This solution cleans url params on tab change, so search params(filters, sort and range) are not applied anymore to other tabs (and lists).
来源:https://stackoverflow.com/questions/59883643/how-to-not-change-the-url-on-list-filtering-with-react-admin