- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
假设我有一条路线/customers,其中 List 客户 正在呈现。在同一条路线上还有一个 side drawer展示。那个抽屉包含一个带有 Filter 的列表帮助主题。
当我开始在侧抽屉的过滤器中输入时,url 发生了变化。这是根据 react-admin 的列表过滤器的工作方式。
问题是客户列表注意到路线变化。实际上,它会根据与帮助主题 相关的搜索词开始查询和重新加载客户。当然没有找到客户。
我希望客户列表不会注意到我正在过滤帮助主题。我的目标解决方案是当我输入帮助主题搜索词时,侧抽屉中的列表过滤器不会更改 url。
我如何配置或自定义侧边抽屉中的过滤器以在键入时不更改 url,而是将当前过滤器值存储在组件状态之类的东西中?
实际上,由于过滤器以一种形式存在(通过 react-final-form),它保持自己的状态,所以我可以接受这样的解决方案。但是当然 publishToUrl
不是 Filter 的可用属性。
const MyFilter = props => (
<Filter {...props} publishToUrl={false} >
<TextInput source="title" />
</Filter>
);
相关:
最佳答案
下面的代码会移除 List 组件与 Redux Store 和 Location 的关联,它可以用来在一个页面上显示多个列表
使用这个列表而不是 react 管理员的列表
创建自己的列表组件
import * as React from 'react';
import PropTypes from 'prop-types';
import {
} from 'ra-core';
import {ListView} from 'ra-ui-materialui';
import {useListController} from '../../controller/useListController';
export const TitlePropType = PropTypes.oneOfType([
PropTypes.string,
PropTypes.element,
]);
/**
* List page component
*
* The <List> component renders the list layout (title, buttons, filters, pagination),
* and fetches the list of records from the REST API.
* It then delegates the rendering of the list of records to its child component.
* Usually, it's a <Datagrid>, responsible for displaying a table with one row for each post.
*
* In Redux terms, <List> is a connected component, and <Datagrid> is a dumb component.
*
* The <List> component accepts the following props:
*
* - actions
* - aside
* - component
* - filter (the permanent filter to apply to the query)
* - filters (a React component used to display the filter form)
* - pagination
* - perPage
* - sort
* - title
*
* @example
*
* const PostFilter = (props) => (
* <Filter {...props}>
* <TextInput label="Search" source="q" alwaysOn />
* <TextInput label="Title" source="title" />
* </Filter>
* );
* export const PostList = (props) => (
* <List {...props}
* title="List of posts"
* sort={{ field: 'published_at' }}
* filter={{ is_published: true }}
* filters={PostFilter}
* >
* <Datagrid>
* <TextField source="id" />
* <TextField source="title" />
* <EditButton />
* </Datagrid>
* </List>
* );
*/
export const List = props => {
return <ListView {...props} {...useListController(props)} />;
}
List.propTypes = {
// the props you can change
actions: PropTypes.element,
aside: PropTypes.element,
bulkActionButtons: PropTypes.oneOfType([PropTypes.element, PropTypes.bool]),
children: PropTypes.node,
classes: PropTypes.object,
className: PropTypes.string,
filter: PropTypes.object,
filterDefaultValues: PropTypes.object,
filters: PropTypes.element,
pagination: PropTypes.element,
perPage: PropTypes.number.isRequired,
sort: PropTypes.shape({
field: PropTypes.string,
order: PropTypes.string,
}),
title: TitlePropType,
// the props managed by react-admin
authProvider: PropTypes.func,
hasCreate: PropTypes.bool.isRequired,
hasEdit: PropTypes.bool.isRequired,
hasList: PropTypes.bool.isRequired,
hasShow: PropTypes.bool.isRequired,
location: PropTypes.object,
match: PropTypes.object,
path: PropTypes.string,
resource: PropTypes.string.isRequired,
};
List.defaultProps = {
filter: {},
perPage: 10,
};
Controller /useListController
import { isValidElement, ReactElement, useEffect, useMemo } from 'react';
import inflection from 'inflection';
import { useSelector } from 'react-redux';
import get from 'lodash/get';
import {useCheckMinimumRequiredProps, useTranslate,
useNotify, useGetList, CRUD_GET_LIST, useVersion, useRecordSelection } from 'react-admin';
import { ListParams } from 'ra-core';
import { Sort, RecordMap, Identifier, ReduxState, Record } from 'ra-core';
import {SORT_ASC} from 'ra-core/esm/reducer/admin/resource/list/queryReducer';
import useListParams from './useListParams';
export interface ListProps {
// the props you can change
filter?: object;
filters?: ReactElement<any>;
filterDefaultValues?: object;
pagination?: ReactElement<any>;
perPage?: number;
sort?: Sort;
// the props managed by react-admin
basePath: string;
debounce?: number;
hasCreate?: boolean;
hasEdit?: boolean;
hasList?: boolean;
hasShow?: boolean;
path?: string;
query: ListParams;
resource: string;
[key: string]: any;
}
const defaultSort = {
field: 'id',
order: SORT_ASC,
};
const defaultData = {};
export interface ListControllerProps<RecordType = Record> {
basePath: string;
currentSort: Sort;
data: RecordMap<RecordType>;
defaultTitle: string;
displayedFilters: any;
filterValues: any;
hasCreate: boolean;
hideFilter: (filterName: string) => void;
ids: Identifier[];
loading: boolean;
loaded: boolean;
onSelect: (ids: Identifier[]) => void;
onToggleItem: (id: Identifier) => void;
onUnselectItems: () => void;
page: number;
perPage: number;
resource: string;
selectedIds: Identifier[];
setFilters: (filters: any, displayedFilters: any) => void;
setPage: (page: number) => void;
setPerPage: (page: number) => void;
setSort: (sort: string) => void;
showFilter: (filterName: string, defaultValue: any) => void;
total: number;
version: number;
}
/**
* Prepare data for the List view
*
* @param {Object} props The props passed to the List component.
*
* @return {Object} controllerProps Fetched and computed data for the List view
*
* @example
*
* import { useListController } from 'react-admin';
* import ListView from './ListView';
*
* const MyList = props => {
* const controllerProps = useListController(props);
* return <ListView {...controllerProps} {...props} />;
* }
*/
export const useListController = <RecordType = Record>(
props: ListProps
): ListControllerProps<RecordType> => {
useCheckMinimumRequiredProps('List', ['basePath', 'resource'], props);
const {
basePath,
resource,
hasCreate,
filterDefaultValues,
sort = defaultSort,
perPage = 10,
filter,
debounce = 500,
} = props;
if (filter && isValidElement(filter)) {
throw new Error(
'<List> received a React element as `filter` props. If you intended to set the list filter elements, use the `filters` (with an s) prop instead. The `filter` prop is internal and should not be set by the developer.'
);
}
const translate = useTranslate();
const notify = useNotify();
const version = useVersion();
const [query, queryModifiers] = useListParams({
resource,
filterDefaultValues,
sort,
perPage,
debounce
});
const [selectedIds, selectionModifiers] = useRecordSelection(resource);
/**
* We want the list of ids to be always available for optimistic rendering,
* and therefore we need a custom action (CRUD_GET_LIST) that will be used.
*/
const { ids, total, loading, loaded } = useGetList<RecordType>(
resource,
{
page: query.page,
perPage: query.perPage,
},
{ field: query.sort, order: query.order },
{ ...query.filter, ...filter },
{
action: CRUD_GET_LIST,
onFailure: error =>
notify(
typeof error === 'string'
? error
: error.message || 'ra.notification.http_error',
'warning'
),
}
);
const data = useSelector(
(state: ReduxState): RecordMap<RecordType> =>
get(
state.admin.resources,
[resource, 'data'],
defaultData
) as RecordMap<RecordType>
);
// When the user changes the page/sort/filter, this controller runs the
// useGetList hook again. While the result of this new call is loading,
// the ids and total are empty. To avoid rendering an empty list at that
// moment, we override the ids and total with the latest loaded ones.
const defaultIds = [];
const defaultTotal = 0;
useEffect(() => {
if (
query.page <= 0 ||
(!loading && query.page > 1 && (ids || []).length === 0)
) {
// query for a page that doesn't exist, set page to 1
queryModifiers.setPage(1);
}
}, [loading, query.page, ids, queryModifiers]);
const currentSort = useMemo(
() => ({
field: query.sort,
order: query.order,
}),
[query.sort, query.order]
);
const resourceName = translate(`resources.${resource}.name`, {
smart_count: 2,
_: inflection.humanize(inflection.pluralize(resource)),
});
const defaultTitle = translate('ra.page.list', {
name: resourceName,
});
return {
basePath,
currentSort,
data,
defaultTitle,
displayedFilters: query.displayedFilters,
filterValues: query.filterValues,
hasCreate,
hideFilter: queryModifiers.hideFilter,
ids: typeof total === 'undefined' ? defaultIds : ids,
loaded: loaded || defaultIds.length > 0,
loading,
onSelect: selectionModifiers.select,
onToggleItem: selectionModifiers.toggle,
onUnselectItems: selectionModifiers.clearSelection,
page: query.page,
perPage: query.perPage,
resource,
selectedIds,
setFilters: queryModifiers.setFilters,
setPage: queryModifiers.setPage,
setPerPage: queryModifiers.setPerPage,
setSort: queryModifiers.setSort,
showFilter: queryModifiers.showFilter,
total: typeof total === 'undefined' ? defaultTotal : total,
version,
};
};
export const injectedProps = [
'basePath',
'currentSort',
'data',
'defaultTitle',
'displayedFilters',
'filterValues',
'hasCreate',
'hideFilter',
'ids',
'loading',
'loaded',
'onSelect',
'onToggleItem',
'onUnselectItems',
'page',
'perPage',
'refresh',
'resource',
'selectedIds',
'setFilters',
'setPage',
'setPerPage',
'setSort',
'showFilter',
'total',
'version',
];
export default useListController;
Controller /useListParams
import {useCallback, useMemo, useState} from 'react';
import lodashDebounce from 'lodash/debounce';
import set from 'lodash/set';
import { ListParams } from 'ra-core';
import { Sort, removeKey, removeEmpty } from 'ra-core';
import queryReducer from 'ra-core/esm/reducer/admin/resource/list/queryReducer';
import {SORT_ASC, SET_SORT, SET_PAGE, SET_PER_PAGE, SET_FILTER} from 'ra-core/esm/reducer/admin/resource/list/queryReducer';
interface ListParamsOptions {
resource: string;
perPage?: number;
sort?: Sort;
filterDefaultValues?: object;
debounce?: number;
}
interface Parameters extends ListParams {
filterValues: object;
displayedFilters: {
[key: string]: boolean;
};
requestSignature: any[];
}
interface Modifiers {
changeParams: (action: any) => void;
setPage: (page: number) => void;
setPerPage: (pageSize: number) => void;
setSort: (sort: string) => void;
setFilters: (filters: any, displayedFilters: any) => void;
hideFilter: (filterName: string) => void;
showFilter: (filterName: string, defaultValue: any) => void;
}
const emptyObject = {};
const defaultSort = {
field: 'id',
order: SORT_ASC,
};
const defaultParams = {};
/**
* Get the list parameters (page, sort, filters) and modifiers.
*
* These parameters are merged from 3 sources:
* - the query string from the URL
* - the params stored in the state (from previous navigation)
* - the options passed to the hook (including the filter defaultValues)
*
* @returns {Array} A tuple [parameters, modifiers].
* Destructure as [
* { page, perPage, sort, order, filter, filterValues, displayedFilters, requestSignature },
* { setFilters, hideFilter, showFilter, setPage, setPerPage, setSort }
* ]
*
* @example
*
* const [listParams, listParamsActions] = useListParams({
* resource: 'posts',
* location: location // From react-router. Injected to your component by react-admin inside a List
* filterDefaultValues: {
* published: true
* },
* sort: {
* field: 'published_at',
* order: 'DESC'
* },
* perPage: 25
* });
*
* const {
* page,
* perPage,
* sort,
* order,
* filter,
* filterValues,
* displayedFilters,
* requestSignature
* } = listParams;
*
* const {
* setFilters,
* hideFilter,
* showFilter,
* setPage,
* setPerPage,
* setSort,
* } = listParamsActions;
*/
const useListParams = ({
resource,
filterDefaultValues,
sort = defaultSort,
perPage = 10,
debounce = 500,
}: ListParamsOptions): [Parameters, Modifiers] => {
const [params, setParams] = useState(defaultParams);
const requestSignature = [
resource,
params,
filterDefaultValues,
JSON.stringify(sort),
perPage
];
const query = useMemo(
() =>
getQuery({
params,
filterDefaultValues,
sort,
perPage
}),
requestSignature // eslint-disable-line react-hooks/exhaustive-deps
);
const changeParams = useCallback(action => {
const newParams = queryReducer(query, action);
setParams(newParams);
}, requestSignature); // eslint-disable-line react-hooks/exhaustive-deps
const setSort = useCallback(
(newSort: string) =>
changeParams({ type: SET_SORT, payload: { sort: newSort } }),
requestSignature // eslint-disable-line react-hooks/exhaustive-deps
);
const setPage = useCallback(
(newPage: number) => changeParams({ type: SET_PAGE, payload: newPage }),
requestSignature // eslint-disable-line react-hooks/exhaustive-deps
);
const setPerPage = useCallback(
(newPerPage: number) =>
changeParams({ type: SET_PER_PAGE, payload: newPerPage }),
requestSignature // eslint-disable-line react-hooks/exhaustive-deps
);
const filterValues = query.filter || emptyObject;
const displayedFilterValues = query.displayedFilters || emptyObject;
const debouncedSetFilters = lodashDebounce(
(newFilters, newDisplayedFilters) => {
let payload = {
filter: removeEmpty(newFilters),
displayedFilters: undefined,
};
if (newDisplayedFilters) {
payload.displayedFilters = Object.keys(
newDisplayedFilters
).reduce((filters, filter) => {
return newDisplayedFilters[filter]
? { ...filters, [filter]: true }
: filters;
}, {});
}
changeParams({
type: SET_FILTER,
payload,
});
},
debounce
);
const setFilters = useCallback(
(filters, displayedFilters) =>
debouncedSetFilters(filters, displayedFilters),
requestSignature // eslint-disable-line react-hooks/exhaustive-deps
);
const hideFilter = useCallback((filterName: string) => {
const newFilters = removeKey(filterValues, filterName);
const newDisplayedFilters = {
...displayedFilterValues,
[filterName]: undefined,
};
setFilters(newFilters, newDisplayedFilters);
}, requestSignature); // eslint-disable-line react-hooks/exhaustive-deps
const showFilter = useCallback((filterName: string, defaultValue: any) => {
const newFilters = set(filterValues, filterName, defaultValue);
const newDisplayedFilters = {
...displayedFilterValues,
[filterName]: true,
};
setFilters(newFilters, newDisplayedFilters);
}, requestSignature); // eslint-disable-line react-hooks/exhaustive-deps
return [
{
displayedFilters: displayedFilterValues,
filterValues,
requestSignature,
...query,
},
{
changeParams,
setPage,
setPerPage,
setSort,
setFilters,
hideFilter,
showFilter,
},
];
};
/**
* Check if user has already set custom sort, page, or filters for this list
*
* User params come from the Redux store as the params props. By default,
* this object is:
*
* { filter: {}, order: null, page: 1, perPage: null, sort: null }
*
* To check if the user has custom params, we must compare the params
* to these initial values.
*
* @param {Object} params
*/
export const hasCustomParams = (params: ListParams) => {
return (
params &&
params.filter &&
(Object.keys(params.filter).length > 0 ||
params.order != null ||
params.page !== 1 ||
params.perPage != null ||
params.sort != null)
);
};
/**
* Merge list params from 3 different sources:
* - the query string
* - the params stored in the state (from previous navigation)
* - the props passed to the List component (including the filter defaultValues)
*/
export const getQuery = ({
filterDefaultValues,
params,
sort,
perPage,
}) => {
const query: Partial<ListParams> =
hasCustomParams(params)
? { ...params } : { filter: filterDefaultValues || {} };
if (!query.sort) {
query.sort = sort.field;
query.order = sort.order;
}
if (!query.perPage) {
query.perPage = perPage;
}
if (!query.page) {
query.page = 1;
}
return {
...query,
page: getNumberOrDefault(query.page, 1),
perPage: getNumberOrDefault(query.perPage, 10),
} as ListParams;
};
export const getNumberOrDefault = (
possibleNumber: string | number | undefined,
defaultValue: number
) =>
(typeof possibleNumber === 'string'
? parseInt(possibleNumber, 10)
: possibleNumber) || defaultValue;
export default useListParams;
关于url - 如何不使用 react-admin 更改列表过滤的 url?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59883643/
假设我拥有域 mydomain.com,并且我在服务器上有一个 Web 应用程序,网址为 http://99.99.99.99:1234/MyApplication/startpage.somethi
我正在尝试通过以下方式更新已解析的 URL: u, _ := url.Parse(s) if u.Scheme == "" { u.Scheme = "https" } if u.Path =
如何将 www.somesite.com/api(.*) 映射到 www.somesite.com/$1:9000? (我需要将/api 映射到运行 @ 端口 9000 的 Play 框架应用程序)
我有一个资源结构,如航类 > 座位 > 预订,所以预订属于某个航类的某个座位: http://example.com/jdf_3prGPS4/1/jMBDy46PbNc
我想知道以下网址是否有效。 路径中的点,在主机之后: http://www.example.com/v.b.w..com 主机中的点,作为子域的一部分: http://v.b.w..co.manufa
我有两个域 - crmpicco.co.uk 和 ayrshireminis.com - 如果我浏览到: www.crmpicco.co.uk/mini/new我希望能够重定向到 www.ayrshi
我正在尝试使用 URL 重写和应用程序请求路由来重写到外部 URL。我设置了以下规则: 在规则中,“patternToMatch”是我试
我已经安装了带有 SharePoint 和 Url Rewrite 模块的 IIS 7.0。 是以下句子还是我配置错误才能看到这个结果? Url Redirect 可以将 url 重定向到任何内部(在
我想知道,为了获得良好的 SEO,您必须在 URL 中使用自然语言。您知道字符中单词或短语的最大大小吗?例如: www.me.com/this-is-a-really-long-url.htm 我问这
有人知道在 SEO 友好 URL 中使用逗号有什么问题吗?我正在使用一些在其 SEO 友好 URL 中使用大量逗号的软件;但我 100% 肯定我见过一些程序/平台无法正确识别 URL 并在第一个逗号后
我有一个网站,我正在为所有链接使用干净的 URL。我想知道对于简短的基本 URL 与较长的描述性 URL 有何看法。 例如,如果我的网站是关于 Georgia Bulldog 足球新闻的,那么哪个网站
我正在编写一个类似于 tinyurl 的 URL 缩短器,我想知道如何跟踪已经使用我的服务缩短的 URL?例如,tinyurl 为相同的长 URL 生成相同的小 URL,而不管是谁创建的。如
我是 magento 的新手。我正在开发一个模块。为此,我有一些要显示链接的 css 和 js 文件。我目前有类似 的链接 getSkinUrl('module_tryouts/css/jquery.
我想基于 HTTP_URL 重写 URL 以重定向到不同的端口,同时保留其余的 URL 和查询字符串(如果指定)。例如, http://host/john/page.aspx 应该重定向到 http:
我遇到了以下问题: 我的 Grails (2.2.0) 应用程序具有以下 URL 映射: "/api/clientQuote/$labcode/$cliCode/$quoCode"(controlle
我有一个很长的 URL,它不适合 URL 字段。它一直在修剪。该怎么办?有没有办法增加 SharePoint 2010 中的 URL 字段字符限制? 或者解决方法来容纳长 URL。例如,以下 URL
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题? Update the question所以它是on-topic对于堆栈溢出。 9年前关闭。 Improve this que
我们从客户以前的开发人员那里继承了相当多的 Google Apps 脚本项目。 Apps 脚本通过嵌入式小部件部署在 Google 网站 (sites.google.com) 的各个页面上。每当我们需
我正在编写一些文档,但遇到了一些词汇问题: http://www.example.com/en/public/img/logo.gif 被称为“绝对”网址,对吗? ../../public/img/l
我们从客户以前的开发人员那里继承了相当多的 Google Apps 脚本项目。 Apps 脚本通过嵌入式小部件部署在 Google 网站 (sites.google.com) 的各个页面上。每当我们需
我是一名优秀的程序员,十分优秀!