- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
你知道如何创建客户端列表 Controller 吗?
我检查了 StackOverflow - 我没有找到问题的答案。
有没有一种简单的方法来创建一个资源,该资源在第一页加载时从服务器读取所有记录。然后排序,过滤,分页在客户端完成。还可以选择禁用分页。
我试图从 ra-core 复制 ListController.js
和从 ra-ui-materialui 复制 List.js
并自定义它,但是错误,我可以前进。我不熟悉 react 和制作 PoC。
这里是错误:
TypeError: Cannot read property 'apply' of undefined
(anonymous function)
node_modules/recompose/compose.js:22
19 |
20 | return funcs.reduce(function (a, b) {
21 | return function () {
22 | return a(b.apply(undefined, arguments));
23 | };
24 | });
25 | }
View compiled
./src/ListController.js
src/ListController.js:431
428 | export default compose(
429 | connect(
430 | mapStateToProps,
431 | {
432 | crudGetList: crudGetListAction,
433 | changeListParams: changeListParamsAction,
434 | setSelectedIds: setListSelectedIdsAction,
View compiled
我已经将导入从相对路径更改为导入react-admin
;关于如何修复错误的任何建议?
这是更改后的 ListController.js
文件:
/* eslint no-console: ["error", { allow: ["warn", "error"] }] */
import { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { parse, stringify } from 'query-string';
import { push as pushAction } from 'react-router-redux';
import compose from 'recompose/compose';
import { createSelector } from 'reselect';
import inflection from 'inflection';
import debounce from 'lodash/debounce';
import isEqual from 'lodash/isEqual';
import pickBy from 'lodash/pickBy';
import removeEmpty from 'react-admin';
import queryReducer, {
SET_SORT,
SET_PAGE,
SET_PER_PAGE,
SET_FILTER,
SORT_DESC,
} from 'react-admin';
import { crudGetList as crudGetListAction } from 'react-admin';
import {
changeListParams as changeListParamsAction,
setListSelectedIds as setListSelectedIdsAction,
toggleListItem as toggleListItemAction,
} from 'react-admin';
import translate from 'react-admin';
import removeKey from 'react-admin';
/**
* 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.
*
* Props:
* - title
* - perPage
* - sort
* - filter (the permanent filter to apply to the query)
* - actions
* - filters (a React Element used to display the filter form)
* - pagination
*
* @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 class ListController extends Component {
state = {};
componentDidMount() {
if (
!this.props.query.page &&
!(this.props.ids || []).length &&
this.props.params.page > 1 &&
this.props.total > 0
) {
this.setPage(this.props.params.page - 1);
return;
}
this.updateData();
if (Object.keys(this.props.query).length > 0) {
this.props.changeListParams(this.props.resource, this.props.query);
}
}
componentWillUnmount() {
this.setFilters.cancel();
}
componentWillReceiveProps(nextProps) {
if (
nextProps.resource !== this.props.resource ||
nextProps.query.sort !== this.props.query.sort ||
nextProps.query.order !== this.props.query.order ||
nextProps.query.page !== this.props.query.page ||
nextProps.query.filter !== this.props.query.filter
) {
this.updateData(
Object.keys(nextProps.query).length > 0
? nextProps.query
: nextProps.params
);
}
if (nextProps.version !== this.props.version) {
this.updateData();
}
}
shouldComponentUpdate(nextProps, nextState) {
if (
nextProps.translate === this.props.translate &&
nextProps.isLoading === this.props.isLoading &&
nextProps.version === this.props.version &&
nextState === this.state &&
nextProps.data === this.props.data &&
nextProps.selectedIds === this.props.selectedIds &&
nextProps.total === this.props.total
) {
return false;
}
return true;
}
/**
* Merge list params from 4 different sources:
* - the query string
* - the params stored in the state (from previous navigation)
* - the filter defaultValues
* - the props passed to the List component
*/
getQuery() {
const query =
Object.keys(this.props.query).length > 0
? this.props.query
: { ...this.props.params };
const filterDefaultValues = this.props.filterDefaultValues || {};
query.filter = { ...filterDefaultValues, ...query.filter };
if (!query.sort) {
query.sort = this.props.sort.field;
query.order = this.props.sort.order;
}
if (!query.perPage) {
query.perPage = this.props.perPage;
}
if (!query.page) {
query.page = 1;
}
return query;
}
updateData(query) {
const params = query || this.getQuery();
const { sort, order, page = 1, perPage, filter } = params;
const pagination = {
page: parseInt(page, 10),
perPage: parseInt(perPage, 10),
};
const permanentFilter = this.props.filter;
this.props.crudGetList(
this.props.resource,
pagination,
{ field: sort, order },
{ ...filter, ...permanentFilter }
);
}
setSort = sort => this.changeParams({ type: SET_SORT, payload: sort });
setPage = page => this.changeParams({ type: SET_PAGE, payload: page });
setPerPage = perPage =>
this.changeParams({ type: SET_PER_PAGE, payload: perPage });
setFilters = debounce(filters => {
if (isEqual(filters, this.props.filterValues)) {
return;
}
// fix for redux-form bug with onChange and enableReinitialize
const filtersWithoutEmpty = removeEmpty(filters);
this.changeParams({ type: SET_FILTER, payload: filtersWithoutEmpty });
}, this.props.debounce);
showFilter = (filterName, defaultValue) => {
this.setState({ [filterName]: true });
if (typeof defaultValue !== 'undefined') {
this.setFilters({
...this.props.filterValues,
[filterName]: defaultValue,
});
}
};
hideFilter = filterName => {
this.setState({ [filterName]: false });
const newFilters = removeKey(this.props.filterValues, filterName);
this.setFilters(newFilters);
};
handleSelect = ids => {
this.props.setSelectedIds(this.props.resource, ids);
};
handleUnselectItems = () => {
this.props.setSelectedIds(this.props.resource, []);
};
handleToggleItem = id => {
this.props.toggleItem(this.props.resource, id);
};
changeParams(action) {
const newParams = queryReducer(this.getQuery(), action);
this.props.push({
...this.props.location,
search: `?${stringify({
...newParams,
filter: JSON.stringify(newParams.filter),
})}`,
});
this.props.changeListParams(this.props.resource, newParams);
}
render() {
const {
basePath,
children,
resource,
hasCreate,
data,
ids,
total,
isLoading,
translate,
version,
selectedIds,
} = this.props;
const query = this.getQuery();
const queryFilterValues = query.filter || {};
const resourceName = translate(`resources.${resource}.name`, {
smart_count: 2,
_: inflection.humanize(inflection.pluralize(resource)),
});
const defaultTitle = translate('ra.page.list', {
name: `${resourceName}`,
});
return children({
basePath,
currentSort: {
field: query.sort,
order: query.order,
},
data,
defaultTitle,
displayedFilters: this.state,
filterValues: queryFilterValues,
hasCreate,
hideFilter: this.hideFilter,
ids,
isLoading,
onSelect: this.handleSelect,
onToggleItem: this.handleToggleItem,
onUnselectItems: this.handleUnselectItems,
page: parseInt(query.page || 1, 10),
perPage: parseInt(query.perPage, 10),
refresh: this.refresh,
resource,
selectedIds,
setFilters: this.setFilters,
setPage: this.setPage,
setPerPage: this.setPerPage,
setSort: this.setSort,
showFilter: this.showFilter,
translate,
total,
version,
});
}
}
ListController.propTypes = {
// the props you can change
children: PropTypes.func.isRequired,
filter: PropTypes.object,
filters: PropTypes.element,
filterDefaultValues: PropTypes.object, // eslint-disable-line react/forbid-prop-types
pagination: PropTypes.element,
perPage: PropTypes.number.isRequired,
sort: PropTypes.shape({
field: PropTypes.string,
order: PropTypes.string,
}),
// the props managed by react-admin
authProvider: PropTypes.func,
basePath: PropTypes.string.isRequired,
changeListParams: PropTypes.func.isRequired,
crudGetList: PropTypes.func.isRequired,
data: PropTypes.object, // eslint-disable-line react/forbid-prop-types
debounce: PropTypes.number,
filterValues: PropTypes.object, // eslint-disable-line react/forbid-prop-types
hasCreate: PropTypes.bool.isRequired,
hasEdit: PropTypes.bool.isRequired,
hasList: PropTypes.bool.isRequired,
hasShow: PropTypes.bool.isRequired,
ids: PropTypes.array,
selectedIds: PropTypes.array,
isLoading: PropTypes.bool.isRequired,
location: PropTypes.object.isRequired,
path: PropTypes.string,
params: PropTypes.object.isRequired,
push: PropTypes.func.isRequired,
query: PropTypes.object.isRequired,
resource: PropTypes.string.isRequired,
setSelectedIds: PropTypes.func.isRequired,
toggleItem: PropTypes.func.isRequired,
total: PropTypes.number.isRequired,
translate: PropTypes.func.isRequired,
version: PropTypes.number,
};
ListController.defaultProps = {
debounce: 500,
filter: {},
filterValues: {},
perPage: 10,
sort: {
field: 'id',
order: SORT_DESC,
},
};
const injectedProps = [
'basePath',
'currentSort',
'data',
'defaultTitle',
'displayedFilters',
'filterValues',
'hasCreate',
'hideFilter',
'ids',
'isLoading',
'onSelect',
'onToggleItem',
'onUnselectItems',
'page',
'perPage',
'refresh',
'resource',
'selectedIds',
'setFilters',
'setPage',
'setPerPage',
'setSort',
'showFilter',
'total',
'translate',
'version',
];
/**
* Select the props injected by the ListController
* to be passed to the List children need
* This is an implementation of pick()
*/
export const getListControllerProps = props =>
injectedProps.reduce((acc, key) => ({ ...acc, [key]: props[key] }), {});
/**
* Select the props not injected by the ListController
* to be used inside the List children to sanitize props injected by List
* This is an implementation of omit()
*/
export const sanitizeListRestProps = props =>
Object.keys(props)
.filter(props => !injectedProps.includes(props))
.reduce((acc, key) => ({ ...acc, [key]: props[key] }), {});
const validQueryParams = ['page', 'perPage', 'sort', 'order', 'filter'];
const getLocationPath = props => props.location.pathname;
const getLocationSearch = props => props.location.search;
const selectQuery = createSelector(
getLocationPath,
getLocationSearch,
(path, search) => {
const query = pickBy(
parse(search),
(v, k) => validQueryParams.indexOf(k) !== -1
);
if (query.filter && typeof query.filter === 'string') {
try {
query.filter = JSON.parse(query.filter);
} catch (err) {
delete query.filter;
}
}
return query;
}
);
function mapStateToProps(state, props) {
const resourceState = state.admin.resources[props.resource];
return {
query: selectQuery(props),
params: resourceState.list.params,
ids: resourceState.list.ids,
selectedIds: resourceState.list.selectedIds,
total: resourceState.list.total,
data: resourceState.data,
isLoading: state.admin.loading > 0,
filterValues: resourceState.list.params.filter,
version: state.admin.ui.viewVersion,
};
}
export default compose(
connect(
mapStateToProps,
{
crudGetList: crudGetListAction,
changeListParams: changeListParamsAction,
setSelectedIds: setListSelectedIdsAction,
toggleItem: toggleListItemAction,
push: pushAction,
}
),
translate
)(ListController);
最佳答案
用自定义 dataProvider
处理这个用例会更容易.
每次您在 ListView 中执行操作(排序、过滤等)时,React Admin 都会向数据提供者询问数据。
例如,假设我们要列出用户,然后按性别筛选,然后按年龄排序。将使用以下参数调用数据提供程序三次:
dataProvider('GET_LIST', 'user', { sort: defaultSort, filters: defaultFilters });
dataProvider('GET_LIST', 'user', { sort: defaultSort, filters: { gender: 'm' } });
dataProvider('GET_LIST', 'user', { sort: { field: 'age', order: 'DESC' }, filters: { gender: 'm' } });
因此,为了实现您想要的行为,您的自定义数据提供程序应该是这样的:
// customDataResolver.js
import simpleRestProvider from 'ra-data-simple-rest';
const restDataProvider = simpleRestDataProvider('http://example.com/api');
let users; // In-memory cache (but you can write in storage or something)
export default (type, resource, params) => {
if (type === 'GET_LIST' && resource === 'users') {
if (!users) {
return restDataProvider(type, resource, params)
.then((data) => {
users = data;
return data;
});
}
return users
.sort(sortBy(params.sort))
.filter(filterBy(params.filter));
};
return restDataProvider(type, resource, params);
};
关于react-admin 如何创建客户端列表 Controller ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51929058/
前言: 有时候,一个数据库有多个帐号,包括数据库管理员,开发人员,运维支撑人员等,可能有很多帐号都有比较大的权限,例如DDL操作权限(创建,修改,删除存储过程,创建,修改,删除表等),账户多了,管理
所以我用 Create React App 创建并设置了一个大型 React 应用程序。最近我们开始使用 Storybook 来处理和创建组件。它很棒。但是,当我们尝试运行或构建应用程序时,我们不断遇
遵循我正在创建的控件的代码片段。这个控件用在不同的地方,变量也不同。 我正在尝试编写指令来清理代码,但在 {{}} 附近插入值时出现解析错误。 刚接触 Angular ,无法确定我错过了什么。请帮忙。
我正在尝试创建一个 image/jpeg jax-rs 提供程序类,它为我的基于 post rest 的 Web 服务创建一个图像。我无法制定请求来测试以下内容,最简单的测试方法是什么? @POST
我一直在 Windows 10 的模拟器中练习 c。后来我改用dev C++ IDE。当我在 C 中使用 FILE 时。创建的文件的名称为 test.txt ,而我给出了其他名称。请帮助解决它。 下面
当我们创建自定义 View 时,我们将 View 文件的所有者设置为自定义类,并使用 initWithFrame 或 initWithCode 对其进行实例化。 当我们创建 customUITable
我正在尝试为函数 * Producer 创建一个线程,但用于创建线程的行显示错误。我为这句话加了星标,但我无法弄清楚它出了什么问题...... #include #include #include
今天在做项目时,遇到了需要创建JavaScript对象的情况。所以Bing了一篇老外写的关于3种创建JavaScript对象的文章,看后跟着打了一遍代码。感觉方法挺好的,在这里与大家分享一下。 &
我正在阅读将查询字符串传递给 Amazon 的 S3 以进行身份验证的文档,但似乎无法理解 StringToSign 的创建和使用方式。我正在寻找一个具体示例来说明 (1) 如何构造 String
前言:我对 C# 中任务的底层实现不太了解,只了解它们的用法。为我在下面屠宰的任何东西道歉: 对于“我怎样才能开始一项任务但不等待它?”这个问题,我找不到一个好的答案。在 C# 中。更具体地说,即使任
我有一个由一些复杂的表达式生成的 ILookup。假设这是按姓氏查找人。 (在我们简单的世界模型中,姓氏在家庭中是唯一的) ILookup families; 现在我有两个对如何构建感兴趣的查询。 首
我试图创建一个 MSI,其中包含 和 exe。在 WIX 中使用了捆绑选项。这样做时出错。有人可以帮我解决这个问题。下面是代码: 错误 error LGH
在 Yii 中,Create 和 Update 通常使用相同的形式。因此,如果我在创建期间有电子邮件、密码、...other_fields...等字段,但我不想在更新期间专门显示电子邮件和密码字段,但
上周我一直在努力创建一个给定一行和一列的 QModelIndex。 或者,我会满足于在已经存在的 QModelIndex 中更改 row() 的值。 任何帮助,将不胜感激。 编辑: QModelInd
出于某种原因,这不起作用: const char * str_reset_command = "\r\nReset"; const char * str_config_command = "\r\nC
现在,我有以下由 original.df %.% group_by(Category) %.% tally() %.% arrange(desc(n)) 创建的 data.frame。 DF 5),
在今天之前,我使用/etc/vim/vimrc来配置我的vim设置。今天,我想到了创建.vimrc文件。所以,我用 touch .vimrc cat /etc/vim/vimrc > .vimrc 所
我可以创建一个 MKAnnotation,还是只读的?我有坐标,但我发现使用 setCooperative 手动创建 MKAnnotation 并不容易。 想法? 最佳答案 MKAnnotation
在以下代码中,第一个日志语句按预期显示小数,但第二个日志语句记录 NULL。我做错了什么? NSDictionary *entry = [[NSDictionary alloc] initWithOb
我正在使用与此类似的代码动态添加到数组; $arrayF[$f+1][$y][$x+1] = $value+1; 但是我在错误报告中收到了这个: undefined offset :1 问题:尝试创
我是一名优秀的程序员,十分优秀!