- 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/
如标题所示,ans_list是一个答案列表,ans_index是一个数字(答案在词汇表中的索引,但与atm无关) 这里生成的 tree.anslist 是什么? (例如,仅针对第一个),忽略迭代。 f
我目前将用户的输入存储在逗号分隔的列表中,如下所示: Userid | Options 1 | 1,2,5 用户在一个数组形式中勾选一组选项,然后用逗号连接起来 1,2,5 然后 MySQ
我目前将用户的输入存储在逗号分隔的列表中,如下所示: Userid | Options 1 | 1,2,5 用户在一个数组形式中勾选一组选项,然后用逗号连接起来 1,2,5 然后 MySQ
我想知道如何完全展平列表和包含它们的东西。除其他外,我想出了一个解决方案,它可以将具有多个元素的东西滑倒并将它们放回原处,或者在滑倒后将具有一个元素的东西拿走。 这与 How do I “flatte
我想知道如何完全展平列表和包含它们的东西。除其他外,我想出了一个解决方案,它可以将具有多个元素的东西滑倒并将它们放回原处,或者在滑倒后将带有一个元素的东西拿走。 这与 How do I “flatte
这个问题已经有答案了: Convert nested list to 2d array (3 个回答) 已关闭 7 年前。 java中有没有快捷方式可以转换 List> 到 String[][] ?
我在排序时遇到问题 List> 。我创建了一个自定义比较器,在其中编写了对数据进行排序的代码。 public class CustomComparator implements Comparator
这个问题已经有答案了: 已关闭10 年前。 Possible Duplicate: Java Generics: Cannot cast List to List? 我只是想知道为什么下面的java代
试图想出一个 LINQy 方法来做到这一点,但我什么也没想到。 我有一个对象列表<>,其中包含一个属性,该属性是逗号分隔的字母代码列表: lst[0].codes = "AA,BB,DD" lst[1
假设我有这些任务: points = [] point = (1, 2) 我怎么会这样做: points += point 它工作得很好,并且给了我点 = [1, 2]。但是,如果我这样做: poin
如何在 scala 中将 List[Task[List[Header]]] 类型转换为 Task[List[Header]]。 我有一个方法返回 Task[List[Header]] 并多次调用 do
如何在 Java 中查找二维列表的元素? 我有一个参数为 List> 的函数我想知道如何找到这个列表的行和列。 最佳答案 如果你喜欢 List> obj 然后你就可以像这样访问 obj.get(cur
分配 List到 List工作正常。 分配 List>到 List>不编译。 代码 public class Main { public static void main(String[] a
我正在用 Java 编写一个方法,该方法必须接收并迭代 Serializable 的 List。 有什么区别: public void myMethod(List list) { } 和 public
我看到很多人想用 mvvm 更新网格/列表/树的一部分,但他们不想刷新整个列表。 对于所有遇到此问题的人,我做了以下示例。 希望这对你有用。 最佳答案 这是一个简单的例子。整个代码中最重要的是: Bi
我正在为现有的 C++ 库编写包装器,该库使用列表,其中 T 是自定义结构。我被建议使用 vector 而不是列表,但我试图避免修改库。 为了更好地理解这个场景,我做了一个简单的应用程序,使用一个列表
List list List list 这两种声明有什么区别吗? 谢谢, 最佳答案 是的。 List可以包含所有派生自 Base 的不同事物的混合物. List包含同质项(从某种意义上说,它们必须全部
有人可以尽可能详细地解释以下类型之间的区别吗? List List List 让我更具体一点。我什么时候想使用 // 1 public void CanYouGiveMeAnAnswer(List l
我有一个元组列表,每个元组都是一对列表。所以我的数据看起来像: mylist = [(['foo', 'bar'], ['bar', 'bar']),(['bar', 'bar'],['bar', '
也许是一个时髦的标题,但我遇到了以下问题: 给定一个类型为 (a * b) list 的列表,我想创建一个类型为 (a * b list) list 的新列表。一个例子: 给定列表 let testL
我是一名优秀的程序员,十分优秀!